// ToolsListerFrame.java
// $Id: ToolsListerFrame.java,v 1.7 1998/05/27 12:59:56 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1998.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.jigsaw.cvs ;

import java.io.* ;
import java.util.* ;

import org.w3c.tools.resources.*;
import org.w3c.tools.sorter.*;
import org.w3c.www.mime.*;
import org.w3c.jigsaw.forms.*;
import org.w3c.jigsaw.http.* ;
import org.w3c.jigsaw.html.* ;
import org.w3c.jigsaw.frames.* ;
import org.w3c.www.http.* ;
import org.w3c.tools.resources.event.*;

/**
 * Emit the content of its parent directory.
 */
public class ToolsListerFrame extends PostableFrame 
                              implements StructureChangedListener 
{
    
    private boolean invalid = true;

    private ResourceReference dirResourceRef = null;

    protected ResourceReference getDirResourceRef() {
	if (invalid || (dirResourceRef == null)) {
	    dirResourceRef = getResource().getParent();
	}
	return dirResourceRef;
    }

    public void registerResource(FramedResource resource) {
	super.registerOtherResource(resource);
	dirResourceRef = resource.getParent();
	try {
	    FramedResource fres = (FramedResource)dirResourceRef.lock();
	    // register us as a listener 
	    fres.addStructureChangedListener(this);
	} catch(InvalidResourceException ex) {
	    ex.printStackTrace();
	} finally {
	    dirResourceRef.unlock();
	}
	invalid = false;
    }

    /**
     * Unused here.
     */
    public void resourceModified(StructureChangedEvent evt) { }

    /**
     * Unused here.
     */
    public void resourceCreated(StructureChangedEvent evt) { }
    
    public void resourceUnloaded(StructureChangedEvent evt){ }

    /**
     * A resource is about to be removed
     * This handles the <code>RESOURCE_REMOVED</code> kind of events.
     * @param evt The event describing the change.
     */

    public void resourceRemoved(StructureChangedEvent evt) {
	invalid = true;
    }
    
    public synchronized Reply getDirectoryListing(Request request)
	throws ProtocolException, NotAProtocolException
    {
	DirectoryResource dirResource = null;
	try {
	    dirResource = (DirectoryResource) getDirResourceRef().lock();
	    if (dirResource == null) 
		throw new NotAProtocolException("parent is NOT a "+
						"DirectoryResource. ("+
						resource.getIdentifier()+")");
	    if (! dirResource.verify()) {
		// the directory was deleted, but we can't delete it here
		// (Multiple Locks)
		// Emit an error back:
		Reply error = request.makeReply(HTTP.NOT_FOUND) ;
		error.setContent ("<h1>Document not found</h1>"+
				  "<p>The document "+
				  request.getURL()+
				  " is indexed but not available."+
				  "<p>The server is misconfigured.") ;
		throw new HTTPException (error) ;
	    }
	    // Have we already an up-to-date computed a listing ?
	    if ((listing == null) 
		|| (dirResource.getDirectory().lastModified() > listing_stamp)
		|| (dirResource.getLastModified() > listing_stamp)
		|| (getLastModified() > listing_stamp)) {
		
		Class httpClass = null;
		try {
		    httpClass=Class.forName("org.w3c.jigsaw.frames.HTTPFrame");
		} catch (ClassNotFoundException ex) {
		    httpClass = null;
		}
		
		Enumeration enum = dirResource.enumerateResourceIdentifiers() ;
		Vector        resources = Sorter.sortStringEnumeration(enum) ;
		HtmlGenerator g = new HtmlGenerator("Directory of "+
						  dirResource.getIdentifier());
		// Add style link
		addStyleSheet(g);
		g.append("<H1>"+dirResource.getIdentifier()+"</H1>");
		// Link to the parent, when possible:
		if ( dirResource.getParent() != null )
		    g.append("<P><A HREF=\"..\">Parent</A><BR>");
		g.append("\n<FORM METHOD=\"POST\">\n");
		// List the children:
		for (int i = 0 ; i < resources.size() ; i++) {
		    String       name     = (String) resources.elementAt(i);
		    ResourceReference rr = null;
		    rr = dirResource.lookup(name);
		    FramedResource resource = null;
		    try {
			resource = (FramedResource) rr.lock();
			HTTPFrame itsframe = null;
			if (httpClass != null)
			    itsframe = (HTTPFrame)resource.getFrame(httpClass);
			g.append("<INPUT TYPE=\"CHECKBOX\" NAME=\"" + name
				 + "\"> ");
			if (itsframe != null) {
			    // Icon first, if available
			    String icon = itsframe.getIcon() ;
			    if ( icon != null ) 
				g.append("<IMG SRC=\""+
					 getIconDirectory() +"/" + icon+
					 "\">");
			    // Resource's name with link:
			    g.append("<A HREF=\"" 
				     , resource.getURLPath()
				     , "\">"+name+"</A>");
			    // resource's title, if any:
			    String title = itsframe.getTitle();
			    if ( title != null )
				g.append(" "+title);
			    g.append("<BR>\n");
			} else {
			    // Resource's name with link:
			    g.append("<A HREF=\"" 
				     , resource.getURLPath()
				     , "\">"+name+"</A>"+" No HTTP Frame!");
			    g.append("<BR>\n");
			}
		    } catch (InvalidResourceException ex) {
			g.append(name +
				 " cannot be loaded (server misconfigured)");
			g.append("<BR>");
			continue;
		    } finally { 
			rr.unlock();
		    }
		}
		g.append("</P><INPUT TYPE=\"SUBMIT\" NAME=\"SUBMIT\" VALUE=\""+
			 "Delete Selected Files\"></FORM>\n");
		g.close() ;
		listing_stamp = getLastModified() ;
		listing       = g ;
	    } else if ( checkIfModifiedSince(request) == COND_FAILED ) {
		// Is it an IMS request ?
		return createDefaultReply(request, HTTP.NOT_MODIFIED) ;
	    }
	} catch (InvalidResourceException ex) {
	    return createDefaultReply(request, HTTP.INTERNAL_SERVER_ERROR);
	} finally {
	    getDirResourceRef().unlock();
	}
	// New content or need update:
	Reply reply = createDefaultReply(request, HTTP.OK) ;
	reply.setLastModified(listing_stamp) ;
	reply.setStream(listing) ;
	return reply ;
    }

    protected Reply getOtherResource (Request request) 
	throws ProtocolException, NotAProtocolException  
    {
	return getDirectoryListing(request);
    }

    /**
     * Handle the form submission, after posted data parsing.
     * <p>This method ought to be abstract, but for reasonable reason, it
     * will just dump (parsed) the form content back to the client, so that it
     * can be used for debugging.
     * @param request The request proper.
     * @param data The parsed data content.
     * @exception ProtocolException If form data processing failed.
     * @see org.w3c.jigsaw.forms.URLDecoder
     */
    
    public Reply handle (Request request, URLDecoder data)
	throws ProtocolException
    {
	Reply r;
	Enumeration   e = data.keys() ;
	while ( e.hasMoreElements () ) {
	    String name = (String) e.nextElement() ;
	    if (name.equals("SUBMIT"))
		continue;
	    // delete file now... avoit deleting CVS and lister
	    // (should be in an attribute)
	    synchronized (this) {
		DirectoryResource dr;
		Resource toDeleteRes;
		ResourceReference rr;
		File dir, toDeleteFile;
		try {
		    dr = (DirectoryResource) getDirResourceRef().lock();
		    dir = dr.getDirectory();
		    System.out.println("Deleting " + name);
		    rr = dr.lookup(name);
		    if (rr != null) {
			try {
			    toDeleteFile = new File(dir, name);
			    toDeleteFile.delete();
			} catch (Exception ex) {
			    // fancy message. file not present
			    // Or security manager forbiding deletion.
			}
			// and now, at least remove the resource
			try {
			    toDeleteRes = (Resource) rr.lock();
			    toDeleteRes.delete();
			} catch (Exception ex) {
			    // some other locks... or pb with the resource
			} finally {
			    rr.unlock();
			}
		    }
		} catch (Exception ex) {
		    // some other locks... abort
		} finally {
		    getDirResourceRef().unlock();
		}
	    }
	}
	try {
	    r = getDirectoryListing(request);
	} catch (NotAProtocolException ex) {
	    r = createDefaultReply(request, HTTP.INTERNAL_SERVER_ERROR);
	}
	return r;
    }
}
