/*
 *    GeoTools - OpenSource mapping toolkit
 *    http://geotools.org
 *    (C) 2005-2006, Geotools Project Managment Committee (PMC)
 *    (C) 2005, Institut de Recherche pour le Développement
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation; either
 *    version 2.1 of the License, or (at your option) any later version.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 */
package org.geotools.image.io;

// J2SE dependencies
import java.io.Serializable;
import java.util.EventListener;
import javax.swing.event.EventListenerList;
import javax.imageio.ImageReader;
import javax.imageio.event.IIOReadWarningListener;
import javax.imageio.event.IIOReadProgressListener;

// Geotools dependencies
import org.geotools.resources.XArray;


/**
 * A container of image I/O listeners. This class provides a set of {@code addFooListener(...)}
 * and {@code removeFooListener(...)} methods for adding and removing various listeners, and a
 * {@code addListenersTo(...)} method for copying listeners to the an image reader. This class is
 * convenient when {@code ImageReader.addFooListener(...)} can't be invoked directly because the
 * {@link ImageReader} instance is not yet know or available.
 *
 * @since 2.1
 * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/coverage/src/main/java/org/geotools/image/io/IIOListeners.java $
 * @version $Id: IIOListeners.java 20970 2006-08-11 07:53:22Z jgarnett $
 * @author Martin Desruisseaux
 *
 * @todo Add other listener types.
 */
public class IIOListeners implements Serializable {
    /**
     * For compatibility with different versions.
     */
    private static final long serialVersionUID = 6944397966242054247L;

    /**
     * The listener categories for read operations.
     */
    private static final Class[] READ = {
        IIOReadProgressListener.class,
        IIOReadWarningListener .class
    };

    /**
     * List of listeners.
     */
    private final EventListenerList listeners = new EventListenerList();
    
    /**
     * Creates a new instance of {@code IIOListeners}.
     */
    public IIOListeners() {
    }
    
    /**
     * Adds an {@code IIOReadProgressListener} to the list of registered progress listeners.
     */
    public void addIIOReadProgressListener(final IIOReadProgressListener listener) {
        listeners.add(IIOReadProgressListener.class, listener);
    }
    
    /**
     * Removes an {@code IIOReadProgressListener} from the list of registered progress listeners.
     */
    public void removeIIOReadProgressListener(final IIOReadProgressListener listener) {
        listeners.remove(IIOReadProgressListener.class, listener);
    }
        
    /**
     * Adds an {@code IIOReadWarningListener} to the list of registered warning listeners.
     */
    public void addIIOReadWarningListener(final IIOReadWarningListener listener) {
        listeners.add(IIOReadWarningListener.class, listener);
    }
    
    /**
     * Removes an {@code IIOReadWarningListener} from the list of registered warning listeners.
     */
    public void removeIIOReadWarningListener(final IIOReadWarningListener listener) {
        listeners.remove(IIOReadWarningListener.class, listener);
    }

    /**
     * Returns all {@linkplain IIOReadProgressListener read progress} and
     * {@linkplain IIOReadWarningListener read warning} listeners.
     */
    public EventListener[] getReadListeners() {
        return getListeners(READ);
    }

    /**
     * Returns all listeners of the given classes.
     */
    private EventListener[] getListeners(final Class[] categories) {
        int   count = 0;
        final Object[] list = listeners.getListenerList();
        final EventListener[] listeners = new EventListener[list.length/2];
   add: for (int i=0; i<list.length; i+=2) {
            final Class type = (Class) list[i];
            for (int j=categories.length; --j>=0;) {
                if (type.equals(categories[i])) {
                    /*
                     * Found a listener in one of the specified categories.
                     * Ensure that it was not already added in the list.
                     */
                    final EventListener candidate = (EventListener)list[i+1];
                    for (int k=count; --k>=0;) {
                        if (listeners[k] == candidate) {
                            // Avoid duplication.
                            continue add;
                        }
                    }
                    listeners[count++] = candidate;
                    continue add;
                }
            }
        }
        return (EventListener[]) XArray.resize(listeners, count);
    }

    /**
     * Add all listeners registered in this object to the specified image reader.
     */
    public void addListenersTo(final ImageReader reader) {
        final Object[] listeners = this.listeners.getListenerList();
        for (int i=0; i<listeners.length;) {
            final Object classe   = listeners[i++];
            final Object listener = listeners[i++];
            if (IIOReadProgressListener.class.equals(classe)) {
                final IIOReadProgressListener l = (IIOReadProgressListener) listener;
                reader.removeIIOReadProgressListener(l); // Ensure singleton
                reader.   addIIOReadProgressListener(l);
                continue;
            }
            if (IIOReadWarningListener.class.equals(classe)) {
                final IIOReadWarningListener l = (IIOReadWarningListener) listener;
                reader.removeIIOReadWarningListener(l); // Ensure singleton
                reader.   addIIOReadWarningListener(l);
                continue;
            }
        }
    }
}
