/*****************************************************************************
 * Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License Version
 * 1.0 (the "License"). You may not use this file except in compliance with
 * the License. A copy of the License is available at http://www.sun.com/
 *
 * The Original Code is the CVS Client Library.
 * The Initial Developer of the Original Code is Robert Greig.
 * Portions created by Robert Greig are Copyright (C) 2000.
 * All Rights Reserved.
 *
 * Contributor(s): Robert Greig.
 *****************************************************************************/
package org.netbeans.lib.cvsclient.event;

import java.util.*;

import org.netbeans.lib.cvsclient.admin.*;
import org.netbeans.lib.cvsclient.file.*;

/**
 * This class is responsible for firing CVS events to registered listeners.
 * It can either fire events as they are generated or wait until a suitable
 * checkpoint and fire many events at once. This can prevent event storms
 * from degrading system performance.
 *
 * @author Robert Greig
 */
public final class EventManager
		implements IEventSender, ICvsListenerRegistry {

	// Fields =================================================================

	private final List<ITerminationListener> terminationListeners = new ArrayList<ITerminationListener>();
	private final List<IMessageListener> messageListener = new ArrayList<IMessageListener>();
	private final List<IModuleExpansionListener> moduleExpansionListeners = new ArrayList<IModuleExpansionListener>();
	private final List<IEntryListener> entryListeners = new ArrayList<IEntryListener>();
	private final List<IFileInfoListener> fileInfoListeners = new ArrayList<IFileInfoListener>();
	private final List<IDirectoryListener> directoryListeners = new ArrayList<IDirectoryListener>();

	// Setup ==================================================================

	public EventManager() {
	}

	// Accessing ==============================================================

	public synchronized void addTerminationListener(ITerminationListener listener) {
		terminationListeners.add(listener);
	}

	public synchronized void removeTerminationListener(ITerminationListener listener) {
		terminationListeners.remove(listener);
	}

	public synchronized void addMessageListener(IMessageListener listener) {
		messageListener.add(listener);
	}

	public synchronized void removeMessageListener(IMessageListener listener) {
		messageListener.remove(listener);
	}

	public synchronized void addModuleExpansionListener(IModuleExpansionListener listener) {
		moduleExpansionListeners.add(listener);
	}

	public synchronized void removeModuleExpansionListener(IModuleExpansionListener listener) {
		moduleExpansionListeners.remove(listener);
	}

	public void addEntryListener(IEntryListener listener) {
		entryListeners.add(listener);
	}

	public void removeEntryListener(IEntryListener listener) {
		entryListeners.remove(listener);
	}

	public synchronized void addFileInfoListener(IFileInfoListener listener) {
		fileInfoListeners.add(listener);
	}

	public synchronized void removeFileInfoListener(IFileInfoListener listener) {
		fileInfoListeners.remove(listener);
	}

	public synchronized void addDirectoryListener(IDirectoryListener listener) {
		directoryListeners.add(listener);
	}

	public synchronized void removeDirectoryListener(IDirectoryListener listener) {
		directoryListeners.remove(listener);
	}

	// Actions ================================================================

	public void notifyTerminationListeners(boolean error) {
		final ITerminationListener[] copiedListeners;
		synchronized (this) {
			if (terminationListeners.size() == 0) {
				return;
			}

			copiedListeners = new ITerminationListener[terminationListeners.size()];
			terminationListeners.toArray(copiedListeners);
		}

		for (ITerminationListener copiedListener : copiedListeners) {
			copiedListener.commandTerminated(error);
		}
	}

	public void notifyMessageListeners(String message, boolean error, boolean tagged) {
		final IMessageListener[] copiedListeners;
		synchronized (this) {
			if (messageListener.size() == 0) {
				return;
			}

			copiedListeners = new IMessageListener[messageListener.size()];
			messageListener.toArray(copiedListeners);
		}

		for (IMessageListener copiedListener : copiedListeners) {
			copiedListener.messageSent(message, error, tagged);
		}
	}

	public void notifyModuleExpansionListeners(String module) {
		final IModuleExpansionListener[] copiedListeners;
		synchronized (this) {
			if (moduleExpansionListeners.size() == 0) {
				return;
			}

			copiedListeners = new IModuleExpansionListener[moduleExpansionListeners.size()];
			moduleExpansionListeners.toArray(copiedListeners);
		}

		for (IModuleExpansionListener copiedListener : copiedListeners) {
			copiedListener.moduleExpanded(module);
		}
	}

	public void notifyFileInfoListeners(Object fileInfoContainer) {
		final IFileInfoListener[] copiedListeners;
		synchronized (this) {
			if (fileInfoListeners.size() == 0) {
				return;
			}

			copiedListeners = new IFileInfoListener[fileInfoListeners.size()];
			fileInfoListeners.toArray(copiedListeners);
		}

		for (IFileInfoListener copiedListener : copiedListeners) {
			copiedListener.fileInfoGenerated(fileInfoContainer);
		}
	}

	public void notifyEntryListeners(FsFilePath fsFile, Entry entry) {
		final IEntryListener[] copiedListeners;
		synchronized (this) {
			if (entryListeners.size() == 0) {
				return;
			}

			copiedListeners = new IEntryListener[entryListeners.size()];
			entryListeners.toArray(copiedListeners);
		}

		for (IEntryListener copiedListener : copiedListeners) {
			copiedListener.gotEntry(fsFile, entry);
		}
	}

	public void notifyDirectoryListeners(FsDirectoryPath fsDirectory, boolean setStatic) {
		for (final IDirectoryListener directoryListener : directoryListeners) {
			directoryListener.processingDirectory(fsDirectory);
		}
	}
}