// PutFilter.java
// $Id: PutFilter.java,v 1.3 1997/01/17 09:51:13 abaird Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.jigsaw.filters;

import java.io.*;

import w3c.tools.store.*;
import w3c.www.http.*;
import w3c.jigsaw.http.*;
import w3c.jigsaw.resources.*;

public class PutFilter extends ResourceFilter implements ResourceLocker {
    /**
     * Attribute index - The companion PutList resource's URL.
     */
    protected static int ATTR_PUTLIST = -1;

    static {
	Class     c = null;
	Attribute a = null;

	try {
	    c = Class.forName("w3c.jigsaw.filters.PutFilter");
	} catch (Exception ex) {
	    ex.printStackTrace();
	    System.exit(1);
	}
	// Register the PutList URL attribute:
	a = new StringAttribute("put-list"
				, null
				, Attribute.EDITABLE|Attribute.MANDATORY);
	ATTR_PUTLIST = AttributeRegistry.registerAttribute(c, a);
    }

    /**
     * Resolve the companion PutList URL attribute into a resource:
     */

    private PutListResource list = null;
    protected synchronized PutListResource resolvePutListResource() {
	// Prepare for lookup:
	HTTPResource root = null;
	root = ((FilteredResource) getTargetResource()).getServer().getRoot();
	String       u  = getPutListURL();
	if ( u == null )
	    return null;
	// Do the lookup:
	HTTPResource target = null;
	try {
	    LookupState  ls = new LookupState(u);
	    LookupResult lr = new LookupResult(root);
	    root.lookup(ls, lr);
	    target = lr.getTarget();
	} catch (Exception ex) {
	    target = null;
	}
	// Lock it:
	if ((target != null) && (target instanceof PutListResource)) {
	    list = (PutListResource) target;
	    list.lock(this);
	} else {
	    list = null;
	}
	return list;
    }

    /**
     * Our lock on the companion PutList resource has been removed.
     * Clean up our pointer to it.
     * @param resource The resource whose lock has been broken.
     */

    public synchronized void notifyResourceLockBreak(Resource resource) {
	if ( resource == list )
	    list = null;
    }

    /**
     * Get our companion PutListResource's URL.
     * @return The URL encoded as a String, or <strong>null</strong> if
     * undefined.
     */

    public String getPutListURL() {
	return getString(ATTR_PUTLIST, null);
    }

    /**
     * Catch PUTLIST assignments.
     * @param idx The attribute being updated.
     * @param value It's new value.
     */

    public void setValue(int idx, Object value) {
	super.setValue(idx, value);
	if ( idx == ATTR_PUTLIST ) {
	    synchronized(this) {
		list = null;
	    }
	}
    }

    /**
     * Nothing done in the ingoingFilter.
     * We wait until the outgoigFilter.
     * @param request The request that is about to be processsed.
     */

    public Reply ingoingFilter(Request request) {
	return null;
    }
    
    /**
     * Catch successfull PUTs, and keep track of them.
     * @param request The original request.
     * @param reply The original reply.
     * @return Always <strong>null</strong>.
     */

    public Reply outgoingFilter(Request request, Reply reply) {
	// Is this a successfull PUT request ?
	if (request.getMethod().equals("PUT") 
	    && ((reply.getStatus()/100) == 2)) {
	    // Cool, keep track of the modified file:
	    PutListResource l = null;
	    synchronized (this) {
		l = resolvePutListResource();
		if ( l != null )
		    l.registerRequest(request);
	    }
	    // Make sure we did something:
	    if ( l == null ) {
		httpd s = ((FilteredResource) getTargetResource()).getServer();
		s.errlog(getClass().getName()
			 + ": unable to resolve companion PutListResource at "
			 + getPutListURL());
	    }
	}
	return null;
    }


    public void initialize(Object values[]) {
	super.initialize(values);
    }

}
