/*******************************************************************************
 * Copyright (c) 2005 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.bpel.ui.util;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.Notifier;

/**
 * An adapter which automatically keeps track of the notifiers it has been added to
 * (so it may be conveniently removed).
 */
public abstract class MultiObjectAdapter implements Adapter {

	// TODO: this was a Set before, I changed it to a List to work around unexpected
	// behavior (eAdapter() lists can contain the same adapter more than once).
	// 
	
	List<Notifier> addedTo = new ArrayList<Notifier>();
	
	/**
	 * Subclasses must override this.
	 * @param n Notification
	 */
	public abstract void notify(Notification n); 
	
	/**
	 * Subclasses may override this (e.g. to add other adapters)
	 * @param target the target
	 */
	public void addedTo(Object target) { }

	/**
	 * Subclasses may override this (e.g. to remove other adapters)
	 * @param target removed from target 
	 */
	public void removedFrom(Object target) { }

	/**
	 * Subclasses may use this helper to add themselves as a listener to a target object.
	 * addToObject() only adds this adapter if it has not already been added to target.
	 *  
	 * @param target 
	 */
		
	
	public void addToObject (Notifier target) {	
		if (addedTo.contains(target)) {
			return ;
		}
		target.eAdapters().add(this);
	}
	
	
	static Notifier [] EMPTY = {};

	/**
	 * Removes this adapter from all notifiers it has been added to.
	 */

	public final void removeFromAll() {
				
		for(Notifier n : addedTo.toArray( EMPTY )) {
			n.eAdapters().remove(this);
		}
		
		if (addedTo.isEmpty() == false)  {			
			throw new IllegalStateException();
		}		
	}
	
	/* Adapter */

	// this is meant for implementation use (i.e. BatchedMultiObjectAdapter).
	// if you override in a subclass, call the super implementation.
	
	protected void doNotify(Notification n) { 
		notify(n); 
	}
	
	/** (non-Javadoc)
	 * @see org.eclipse.emf.common.notify.Adapter#notifyChanged(org.eclipse.emf.common.notify.Notification)
	 */
	
	public final void notifyChanged (Notification n) {
		if (n == null)  {
			throw new IllegalStateException();
		}
		if (n.getEventType() == Notification.REMOVING_ADAPTER) {
			Object notifier = n.getNotifier();
			addedTo.remove(notifier);
			removedFrom(notifier);
		} else {
			doNotify(n);
		}
	}
	
	/**
	 * @see org.eclipse.emf.common.notify.Adapter#isAdapterForType(java.lang.Object)
	 */
	
	public final boolean isAdapterForType (Object type) { 
		return false; 
	}
	
	/**
	 * @see org.eclipse.emf.common.notify.Adapter#getTarget()
	 */
	public final Notifier getTarget() { 
		return null; 
	}
	
	/**
	 * @see org.eclipse.emf.common.notify.Adapter#setTarget(org.eclipse.emf.common.notify.Notifier)
	 */
	public final void setTarget(Notifier newTarget) {
		addedTo.add(newTarget);  // <--- hack
		addedTo(newTarget);
	}
}