// IndexersEditor.java
// $Id: IndexersEditor.java,v 1.3 1997/03/28 15:33:00 abaird Exp $
// (c) COPYRIGHT MIT and INRIA, 1996.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.jigsaw.indexer;

import java.util.* ;
import java.io.*;
import java.net.URLEncoder;

import w3c.tools.store.*;
import w3c.tools.sorter.*;
import w3c.jigsaw.http.* ;
import w3c.jigsaw.resources.* ;
import w3c.jigsaw.forms.* ;
import w3c.jigsaw.formedit.*;
import w3c.www.http.*;
import w3c.jigsaw.html.*;

class TemplateAddHandler extends FormCardHandler {
    ResourceContext   context   = null;
    TemplateContainer container = null ;
    String            url       = null ;

    public String notifyEndProcessing(FormCardResource card, Request request)
	throws FormProcessingException
    {
	String name = (String) card.lookupField("name").getValue() ;
	Class  cls  = (Class) card.lookupField("class").getValue() ;
	if ((name == null) || (cls == null)) {
	    String msg = "Fill in the name of the template, and the class " 
                + " for that template.";
            throw new FormProcessingException (msg) ; 
	} 
	// Create and register the new resource:
	try {
	    HTTPResource resource = (HTTPResource) cls.newInstance() ;
	    container.registerResource(name, resource, null);
	} catch (Exception ex) {
	    ex.printStackTrace();
	    throw new FormProcessingException ("Unable to create "
					       + name
					       + ": "
					       + ex.getMessage());
	}
	return null;
    }


    TemplateAddHandler(ResourceContext context
		       , String url
		       , TemplateContainer container) {
	this.context   = context;
	this.url       = url ;
	this.container = container;
    }

}


class TemplateListHandler extends FormCardHandler {
    TemplateContainer container = null ;
    String            url       = null ;
    Vector            marked    = null ;

    /**
     * Update the catalog list of realms.
     */

    public FormCardResource updateFormCard(FormCardResource card) {
	// FIXME (check for last-modified)
	card.reset() ;
	// Enumerate the available realms:
	Enumeration enum      = container.enumerateResourceIdentifiers() ;
	Vector      templates = Sorter.sortStringEnumeration(enum) ;
	for (int i = 0 ; i < templates.size() ; i++) {
	    String name = (String) templates.elementAt(i) ;
	    card.addField(new CheckBoxField(name
					    , name
					    , url+"/"+URLEncoder.encode(name)
					    , false)) ;
	}
	return card ;
    }

    /**
     * On notifyChange, mark the appropriate realm.
     */

    public void notifyChange(FormFieldInterface field, Object value)
	throws FormFieldException
    {
	if ( marked == null ) 
	    marked = new Vector() ;
	marked.addElement(field.getName()) ;
    }

    /**
     * On notifyEndProcessing, delete all marked realms.
     * @param card The card wose processing is to be finished.
     * @param request The request that trigered the processing.
     * @exception FormProcessingException If the processing failed.
     */

    public String notifyEndProcessing(FormCardResource card, Request request) 
	throws FormProcessingException
    {
	// No realms marked ?
	if ( marked == null )
	    return null ;
	// Remove all marked realms.
	int vsize = marked.size() ;
	for (int i = 0 ; i < vsize ; i++) {
	    String id = (String) marked.elementAt(i);
	    container.delete(id);
	    card.removeField(id) ;
	}
	marked.setSize(0) ;
	return null ;
    }

    TemplateListHandler (String url, TemplateContainer container) {
	this.url       = url ;
	this.container = container ;
    }
}


class TemplateContainerEditor extends FormResource implements ResourceLocker {
    Hashtable         loaded    = null ;
    TemplateContainer container = null; 

    /**
     * Resource locker implementation - Some template is going down.
     * @param resource The template being shutdown.
     */

    public synchronized void notifyResourceLockBreak(Resource r) {
	loaded.remove(r.getIdentifier());
    }

    /**
     * Define the form cards.
     */

    protected void defineFormCards() {
	FormFieldInterface field = null ;
	String             url   = getURLPath() ;
	
	// The card to delete realms:
	FormCardHandler list_handler = new TemplateListHandler(url, container);
	FormCardResource c = defineCard(list_handler
					, "Existing Templates"
					, "Edit Existing Templates");
	c.setOkLabel("Delete");
	list_handler.updateFormCard(c) ;
	// The card to define new templates:
	FormCardHandler add_handler = new TemplateAddHandler(getContext()
							     , url
							     , container);
	c = defineCard(add_handler, "Add Template", "Define a new template.");
	c.setOkLabel("Create");
	// The name of the indexer
	field = new TextField("name", "name", null, null) ;
	c.addField(field) ;
	// The class for the new resource:
	field = new ClassnameField("class", "class", null, null) ;
	c.addField(field);
    }

    /**
     * Lookup in the realms editor for a defined realm.
     * @param state The current lookup state.
     * @return A Resource to edit the realm.
     */

    public boolean lookup(LookupState ls, LookupResult lr) 
	throws HTTPException
    {
	if ( ! ls.hasMoreComponents() ) 
	    return super.lookup(ls, lr);
	String       name = ls.peekNextComponent() ;
	HTTPResource edit = (HTTPResource) loaded.get(name) ;
	// Is an editor available for the realm ?
	if ( edit != null ) {
	    ls.getNextComponent() ;
	    lr.setTarget(edit);
	    return edit.lookup(ls, lr);
	}
	// Install a new editor (if the indexer exists) 
	HTTPResource template = null;
	try {
	    template = (HTTPResource) container.lookup(name);
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	if (template == null) 
	    return super.lookup(ls, lr);
	ls.getNextComponent() ;
	// Create the editor:
	Hashtable defs= new Hashtable(11);
	defs.put("parent", this) ;
	defs.put("url", getURLPath()+"/"+URLEncoder.encode(name));
	defs.put("target", template) ;
	defs.put("context", getContext());
	edit = FormEditorFactory.getEditor(template);
	edit.initialize(defs) ;
	template.lock(this);
	loaded.put(name, edit) ;
	lr.setTarget(edit);
	return edit.lookup(ls, lr);
    }

    /**
     * Initialize the realm editor
     */

    public void initialize(Object values[]) {
	super.initialize(values) ;
	this.loaded    = new Hashtable(11) ;
	defineFormCards() ;
    }

    TemplateContainerEditor(TemplateContainer c, Hashtable defs) {
	this.container = c;
	initialize(defs);
    }
}

class IndexerEditor extends FilteredResource {
    Resource           target      = null;
    HTTPResource       directories = null;
    HTTPResource       extensions  = null;
    String             url         = null;

    /**
     * Lookup in the realm for an editor targeted to some given user.
     * @param state The current lookup state.
     * @exception HTTPException If the user wasn't found.
     */

    public boolean lookup(LookupState ls, LookupResult lr) 
	throws HTTPException
    {
	if ( ! ls.hasMoreComponents() )
	    return super.lookup(ls, lr);
	String name = ls.getNextComponent();
	if ( name.equals("directories") ) {
	    lr.setTarget(directories);
	    return directories.lookup(ls, lr);
	} else if ( name.equals("extensions") ) {
	    lr.setTarget(extensions);
	    return extensions.lookup(ls, lr);
	} 
	lr.setTarget(null);
	return true;
    }

    public Reply get(Request request) 
	throws HTTPException
    {
	HtmlGenerator g = new HtmlGenerator(target.getIdentifier());
	g.append("<p><a href=\""+url+"directories\">directories</a>");
	g.append("<p><a href=\""+url+"extensions\">extensions</a>");
	Reply reply = createDefaultReply(request, HTTP.OK);
	reply.setStream(g);
	reply.addPragma("no-cache");
	reply.setMaxAge(0);
	return reply;
    }

    IndexerEditor(ResourceContext context, String url, Resource target) {
	this.target = target ;
	this.url    = url;
	// Initialize this:
	Hashtable defs = new Hashtable(11);
	defs.put("context", context);
	defs.put("url", url);
	defs.put("identifier", "not-seen");
	initialize(defs);
	// Create the directories editor:
	SampleContainer c = ((SampleResourceIndexer) target).getDirectories();
	defs.put("parent", this) ;
	defs.put("url", url +"/directories");
	defs.put("context", context);
	directories = new TemplateContainerEditor((TemplateContainer) c, defs);
	// And the extensions editor:
	c =  ((SampleResourceIndexer) target).getExtensions();
	defs.put("url", url +"/extensions");
	extensions = new TemplateContainerEditor((TemplateContainer) c, defs);
    }
}

class IndexersAddHandler extends FormCardHandler {
    ResourceContext context = null;
    IndexersCatalog catalog = null ;
    String          url     = null ;

    /**
     * Given a realm name and a realm repository, create a new realm.
     */

    public String notifyEndProcessing(FormCardResource card, Request request)
	throws FormProcessingException
    {
	// Get and check input values:
	String name    = (String) card.lookupField("name").getValue() ;
	if (name == null) {
	    String msg = "Fill in both the indexer name.";
	    throw new FormProcessingException(msg) ;
	}
	// Create the indexer:
	Resource indexer = new SampleResourceIndexer();
	catalog.registerResource(name, indexer, null);
	// Relocate to the realm editor.
	return url+"/"+URLEncoder.encode(name);
    }

    IndexersAddHandler (ResourceContext context
		      , String url
		      , IndexersCatalog catalog) {
	this.context = context;
	this.url     = url ;
	this.catalog = catalog ;
    }

}

class IndexersListHandler extends FormCardHandler {
    IndexersCatalog catalog = null ;
    String          url     = null ;
    Vector          marked  = null ;

    /**
     * Update the catalog list of realms.
     */

    public FormCardResource updateFormCard(FormCardResource card) {
	// FIXME (check for last-modified)
	card.reset() ;
	// Enumerate the available realms:
	Enumeration enum   = catalog.enumerateResourceIdentifiers() ;
	Vector      realms = Sorter.sortStringEnumeration(enum) ;
	for (int i = 0 ; i < realms.size() ; i++) {
	    String name = (String) realms.elementAt(i) ;
	    card.addField(new CheckBoxField(name
					    , name
					    , url+"/"+URLEncoder.encode(name)
					    , false)) ;
	}
	return card ;
    }

    /**
     * On notifyChange, mark the appropriate realm.
     */

    public void notifyChange(FormFieldInterface field, Object value)
	throws FormFieldException
    {
	if ( marked == null ) 
	    marked = new Vector() ;
	marked.addElement(field.getName()) ;
    }

    /**
     * On notifyEndProcessing, delete all marked realms.
     * @param card The card wose processing is to be finished.
     * @param request The request that trigered the processing.
     * @exception FormProcessingException If the processing failed.
     */

    public String notifyEndProcessing(FormCardResource card, Request request) 
	throws FormProcessingException
    {
	// No realms marked ?
	if ( marked == null )
	    return null ;
	// Remove all marked realms.
	int vsize = marked.size() ;
	for (int i = 0 ; i < vsize ; i++) {
	    String id = (String) marked.elementAt(i);
	    catalog.delete(id);
	    card.removeField(id) ;
	}
	marked.setSize(0) ;
	return null ;
    }

    IndexersListHandler (String url, IndexersCatalog catalog) {
	this.url     = url ;
	this.catalog = catalog ;
    }
}

public class IndexersEditor extends FormResource implements ResourceLocker {
    Hashtable       loaded  = null ;
    IndexersCatalog catalog = null ;

    /**
     * Resource locker implementation - Some realm is going down.
     * @param resource The realm being shutdown.
     */

    public synchronized void notifyResourceLockBreak(Resource r) {
	loaded.remove(r.getIdentifier());
    }

    /**
     * Define the forms card.
     */

    protected void defineFormCards() {
	FormFieldInterface field = null ;
	String             url   = getURLPath() ;
	
	// The card to delete realms:
	FormCardHandler list_handler = new IndexersListHandler(url, catalog);
	FormCardResource c = defineCard(list_handler
					, "Indexers"
					, "Edit indexers configuration");
	c.setOkLabel("Delete");
	list_handler.updateFormCard(c) ;
	// The card to define new realms:
	FormCardHandler add_handler = new IndexersAddHandler(getContext()
							     , url
							     , catalog);
	c = defineCard(add_handler, "Add Indexer", "Define a new indexer.");
	c.setOkLabel("Create");
	// The name of the indexer
	field = new TextField("name", "name", null, null) ;
	c.addField(field) ;
    }

    /**
     * Lookup in the realms editor for a defined realm.
     * @param state The current lookup state.
     * @return A Resource to edit the realm.
     */

    public boolean lookup(LookupState ls, LookupResult lr) 
	throws HTTPException
    {
	if ( ! ls.hasMoreComponents() ) 
	    return super.lookup(ls, lr);
	String        name = ls.peekNextComponent() ;
	IndexerEditor edit = (IndexerEditor) loaded.get(name) ;
	// Is an editor available for the realm ?
	if ( edit != null ) {
	    ls.getNextComponent() ;
	    lr.setTarget(edit);
	    return edit.lookup(ls, lr);
	}
	// Install a new editor (if the indexer exists) 
	Resource indexer = null;
	try {
	    indexer = (Resource) catalog.lookup(name);
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	if (indexer == null) 
	    return super.lookup(ls, lr);
	ls.getNextComponent() ;
	edit = new IndexerEditor(getContext()
				 , getURLPath()+"/"+URLEncoder.encode(name)+"/"
				 , indexer);
	indexer.lock(this);
	loaded.put(name, edit) ;
	lr.setTarget(edit);
	return edit.lookup(ls, lr);
    }

    /**
     * Initialize the realm editor
     */

    public void initialize(Object values[]) {
	super.initialize(values) ;
	this.catalog = getServer().getIndexersCatalog() ;
	this.loaded  = new Hashtable(11) ;
	defineFormCards() ;
    }

}
