/*
 * @(#)ActionSequence.java    2.3.3  3 January 2005
 *
 * Copyright 2005
 * College of Computer and Information Science
 * Northeastern University
 * Boston, MA  02115
 *
 * The Java Power Tools software may be used for educational
 * purposes as long as this copyright notice is retained intact
 * at the top of all source files.
 *
 * To discuss possible commercial use of this software, 
 * contact Richard Rasala at Northeastern University, 
 * College of Computer and Information Science,
 * 617-373-2462 or rasala@ccs.neu.edu.
 *
 * The Java Power Tools software has been designed and built
 * in collaboration with Viera Proulx and Jeff Raab.
 *
 * Should this software be modified, the words "Modified from 
 * Original" must be included as a comment below this notice.
 *
 * All publication rights are retained.  This software or its 
 * documentation may not be published in any media either
 * in whole or in part without explicit permission.
 *
 * This software was created with support from Northeastern 
 * University and from NSF grant DUE-9950829.
 */

package edu.neu.ccs.gui;

import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;

/**
 * <p>An ordered collection of <code>ActionListener</code> objects 
 * similar to a <code>{@link List List}</code>; 
 * the sequence itself is an instance of <code>AbstractAction</code>;
 * the <code>actionPerformed</code> method of the sequence executes
 * the <code>actionPerformed</code> method of each listener in its
 * list in order of entry into the list.</p>
 *
 * <p>Prior to version 2.3.3, this class required that its contents
 * satisfy the stronger interface <code>Action</code>.  To avoid
 * the inconvenience of this restriction, certain parameter and
 * return types were changed to require only the weaker interface
 * <code>ActionListener</code>.</p>
 *
 * @author  Jeff Raab
 * @author  Richard Rasala
 * @version 2.3.3
 * @since   1.0
 */
public class ActionSequence 
    extends AbstractAction
    implements Serializable
{
    
    /** The underlying list used for storage of action listeners. */
    protected List actions = null;
    
    
    /**
     * Constructs a sequence using the default
     * underlying linear data structure.
     *
     * @see #ActionSequence(List)
     */
    public ActionSequence() {
        this(null);
    }
    
    
    /**
     * Constructs a sequence using the given
     * underlying linear data structure.
     *
     * If the given structure is <CODE>null</CODE>,
     * the default structure is used.
     *
     * @param l the data structure to be used
     * @see #ActionSequence()
     */
    public ActionSequence(List l) {
        if (l == null)
            l = new ArrayList();
            
        actions = l;
    }
    
    
    ////////////////////
    // ActionListener //
    ////////////////////

    /**
     * <p>If this sequence is enabled then performs the enabled actions
     * within the sequence in order; otherwise does nothing.</p>
     *
     * <p>As of 2.3.3, this sequence may contain objects that implement
     * only the <code>ActionListener</code> interface in which case
     * there is no notion of <i>enabled</i>. Therefore, if the sequence
     * is enabled as a whole, those objects will perform their actions.
     * However, to maintain backward compatibility, if an object in the
     * sequence implements <code>Action</code>, then that object will
     * only perform its action if it is individually enabled as well.</p>
     *  
     * @param evt the action event
     */
    public final void actionPerformed(ActionEvent evt) {
        if (! isEnabled())
            return;
        
        Iterator elements = iterator();
        
        while (elements.hasNext()) {
            Object element = elements.next();

            if (element instanceof Action) {
                Action a = (Action)element;
                
                if (a.isEnabled())
                    a.actionPerformed(evt);
            }
            else
            if (element instanceof ActionListener) {
                ActionListener b = (ActionListener) element;
                b.actionPerformed(evt);
            }
        }
    }
    
    
    ////////////////
    // Public API //
    ////////////////

    /**
     * Inserts the given action listener
     * at the given index in this sequence.
     *
     * @see #add(ActionListener)
     */
    public void add(int index, ActionListener a) {
        if (a == null)
            return;
        
        actions.add(index, a);
    }
    
    
    /**
     * Appends the given action listener
     * to the end of this sequence.
     *
     * @return whether or not the action was successfully appended
     * @see #add(int, ActionListener)
     */
    public boolean add(ActionListener a) {
        if (a == null)
            return false;
        
        return actions.add(a);
    }
    
    
    // The following methods have not been implemented
    // since they are not applicable to this class
    //
    // public boolean addAll(Collection c) {
    // public boolean addAll(int index, Collection c) 
    
    
    /**
     * Removes all of the action listeners from this sequence.
     */
    public void clear() {
        actions.clear();
    }
    
    
    /**
     * Returns <CODE>true</CODE> if the given action listener 
     * is contained in this sequence,
     * or <CODE>false</CODE> if it is not.
     *
     * @see #containsAll(Collection)
     */
    public boolean contains(ActionListener a) {
        if (a == null)
            return false;
        
        return actions.contains(a);
    }
    
    
    /**
     * Returns <CODE>true</CODE> if this sequence contains 
     * all of the elements of the specified collection.
     *
     * @see #contains(ActionListener)
     */
    public boolean containsAll(Collection c) {
        return actions.containsAll(c);
    }
    
    
    /**
     * <p>Returns <CODE>true</CODE> if the given object is
     * an <code>ActionSequence</code> and is equal to this
     * sequence, and <CODE>false</CODE> if it is not.</p>
     */
    public boolean equals(Object object) {
        if (actions == null)
            return false;
        
        if (! (object instanceof ActionSequence))
            return false;
        
        ActionSequence sequence = (ActionSequence) object;
        
        return actions.equals(sequence.actions);
    }
    
    
    /**
     * Returns the action listener at the given index in this
     * sequence.
     */
    public ActionListener get(int index) {
        return (ActionListener)actions.get(index);
    }
    
    
    /**
     * Returns a hash code value for this sequence.
     */
    public int hashCode() {
        if (actions == null)
            return 0;
        
        return actions.hashCode();
    }
    
    
    /**
     * Returns the index in this sequence 
     * of the first occurence of the given action listener, 
     * or -1 if this sequence does not contain this action
     * listener.
     *
     * @see #lastIndexOf(ActionListener)
     */
    public int indexOf(ActionListener a) {
        if (a == null)
            return -1;
        
        return actions.indexOf(a);
    }
    
    
    /**
     * Returns <CODE>true</CODE> if this sequence is empty,
     * and <CODE>false</CODE> if it is not.
     *
     * @see #size()
     */
    public boolean isEmpty() {
        return actions.isEmpty();
    }
    
    
    /**
     * Returns an iterator 
     * over the action listeners in this sequence
     * in proper order.
     *
     * @see #listIterator()
     * @see #listIterator(int)
     */
    public Iterator iterator() {
        return actions.iterator();
    }
    
    
    /**
     * Returns the index in this sequence
     * of the last occurrence of the given action listener,
     * or -1 if this list does not contain this action listener.
     *
     * @see #indexOf(ActionListener)
     */
    public int lastIndexOf(ActionListener a) {
        if (a == null)
            return -1;
        
        return actions.lastIndexOf(a);
    }
    
    
    /**
     * Returns a list iterator 
     * over the action listeners in this sequence in order.
     *
     * @see #listIterator(int)
     * @see #iterator()
     */
    public ListIterator listIterator() {
        return actions.listIterator();
    }
    
    
    /**
     * Returns a list iterator 
     * over the action listeners in this sequence in order, 
     * starting at the given index.
     *
     * @see #listIterator()
     * @see #iterator()
     */
    public ListIterator listIterator(int index) {
        return actions.listIterator(index);
    }
    
    
    /**
     * Removes the action listener at the given index of the
     * sequence.
     *
     * @return the action listener that was removed
     * @see #remove(ActionListener)
     */
    public ActionListener remove(int index) {
        return (ActionListener)actions.remove(index);
    }
    
    
    /**
     * Removes the first occurrence 
     * of the given action listener in this sequence,
     * and returns <CODE>true</CODE>, 
     * or returns <CODE>false</CODE>
     * if this sequence does not contain the action listener.
     *
     * @see #remove(int)
     */
    public boolean remove(ActionListener a) {
        if (a == null)
            return false;
        
        return actions.remove(a);
    }
    
    
    // The following methods have not been implemented
    // since they are not applicable to this class
    //
    // public boolean removeAll(Collection c) 
    // public boolean retainAll(Collection c) 
    
    
    /**
     * Replaces the action listener
     * at the given index in this sequence
     * with the given action listener.
     *
     * @return the action listener that was replaced
     */
    public ActionListener set(int index, ActionListener a) {
        if (a == null)
            return null;
        
        return (ActionListener)actions.set(index, a); 
    }
    
    
    /**
     * Returns the number of action listeners in this sequence.
     *
     * @see #isEmpty()
     */
    public int size() {
        return actions.size();
    }
    
    
    /**
     * Returns an <code>ActionSequence</code> 
     * containing the action listeners in this sequence 
     * from the given starting index, inclusive,
     * to the given ending index, exclusive.
     *
     * @see #listIterator(int)
     */
    public ActionSequence subList(int fromIndex, int toIndex) {
        ActionSequence subsequence = new ActionSequence();
        subsequence.actions = actions.subList(fromIndex, toIndex);
        return subsequence;
    }
    
    
    /**
     * Returns an array 
     * containing the action listeners in this sequence in order.
     *
     * @see #iterator()
     * @see #listIterator()
     */
    public ActionListener[] toArray() {
        return (ActionListener[])
            actions.toArray(new ActionListener[0]);
    }
    
    
    // The following methods have not been implemented
    // since they are not applicable to this class
    //
    // public Object[] toArray(Object[])
    
}
