// ResourceDelegatorImpl.java
// $Id: ResourceDelegatorImpl.java,v 1.3 1997/07/30 14:07:39 ylafon Exp $  
// (c) COPYRIGHT MIT and INRIA, 1997.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.tools.resources.impl;

import w3c.tools.resources.*;

public class ResourceDelegatorImpl {
    /**
     * The target we're implementing delegation support for.
     */
    protected transient ResourceReference target = null;
    /**
     * Our set of delegatee.
     * FIXME The whole question here is how, if possible, will we serialize
     * resource references, and who - if any - should store them.
     */
    protected transient ResourceReference delegatee[] = null;
    protected transient int delegateeLength = 0;

    protected ResourceReference findDelegatee(Class c) {
	for (int i = 0 ; i < delegateeLength ; i++) {
	    ResourceReference rr = delegatee[i];
	    try {
		Resource r = rr.lock();
		if ( c.isInstance(r) )
		    return rr;
	    } finally {
		rr.unlock();
	    }
	}
	return null;
    }

    public synchronized Object getInstanceOf(Class cls) 
	throws ClassCastException
    {
	ResourceReference impl = findDelegatee(cls);
	if ( impl == null )
	    throw new ClassCastException(getClass().getName()
					 + " to " + cls.getName());
	return impl;
    }

    public synchronized boolean isInstanceOf(Class cls) {
	return findDelegatee(cls) != null;
    }

    public synchronized void addDelegatee(ResourceReference d) {
	if ( delegateeLength+1 >= delegatee.length ) {
	    int len = (delegatee.length == 0) ? 2 : delegatee.length;
	    ResourceReference nd[] = new ResourceReference[len<<1];
	    System.arraycopy(delegatee, 0, nd, 0, delegatee.length);
	    delegatee = nd;
	}
	delegatee[delegateeLength++] = d;
    }

    public synchronized void removeDelegatee(ResourceReference d) {
	for (int i = 0 ; i < delegateeLength ; i++) {
	    if ( delegatee[i] == d ) {
		if ( i+1 < delegateeLength )
		    System.arraycopy(delegatee, i+1
				     , delegatee, i, delegateeLength-i-1);
		delegateeLength--;
		return;
	    }
	}
    }

    public synchronized ResourceReference[] getDelegatees() {
	// Trim current set of delegatees:
	if ( delegateeLength != delegatee.length ) {
	    ResourceReference nd[] = new ResourceReference[delegateeLength];
	    System.arraycopy(delegatee, 0, nd, 0, delegateeLength);
	    delegatee = nd;
	}
	return delegatee;
    }

    public ResourceDelegatorImpl(ResourceReference target) {
	// Check that the target has the appropriate property:
	this.target    = target;
	this.delegatee = new ResourceReference[0];
    }
}
