// AdminServer.java
// $Id: AdminServer.java,v 1.12 1998/01/30 14:14:09 bmahe Exp $
// (c) COPYRIGHT MIT and INRIA, 1997.
// Please first read the full copyright statement in file COPYRIGHT.html

package w3c.jigsaw.admin;

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

import w3c.util.*;

import w3c.tools.store.*;
import w3c.www.mime.*;
import w3c.www.http.*;
import w3c.jigsaw.daemon.*;
import w3c.jigsaw.http.*;
import w3c.jigsaw.auth.*;
import w3c.jigsaw.resources.*;

class ServerHandlerManagerResource extends ContainerResource {
    ServerHandlerManager shm = null;
    AdminServer as = null;

    public boolean hasResourceStore() {
	return false;
    }

    public httpd getServer() {
	return as;
    }

    public ResourceStore getResourceStore(ResourceStoreHolder holder) {
	return null;
    }

    public Resource lookup(String name) {
	ServerHandler handler = shm.lookupServerHandler(name);
	if (handler != null) {
	    return handler.getConfigResource();
	} 
	return null;
    }

    public Enumeration enumerateResourceIdentifiers(boolean all) {
	String name;
	Vector v = new Vector();
	Enumeration e = shm.enumerateServerHandlers();
	while(e.hasMoreElements()) {
	    name = (String) e.nextElement();
            if( !(shm.lookupServerHandler(name) instanceof AdminServer)) {
		v.addElement(name);
	    }
	}
	v.addElement("realms");
	v.addElement("control");
	return v.elements(); 
    }

    public HTTPResource createDefaultResource(String name) {
	// This should in fact create a new server handler
	return null;
    }

    public void registerResource(String name
				 , Resource child
				 , Hashtable defs) {
	throw new RuntimeException("Can't register resource there !");
    }

    public void delete(String name) {
	throw new RuntimeException("no delete supported");
    }

    ServerHandlerManagerResource(AdminServer as, ServerHandlerManager shm) {
	this.as = as;
	this.shm = shm;
    }
}

public class AdminServer extends httpd {
    protected ResourceBroker       broker        = null;
    protected ServerHandlerManager shm           = null;
    protected AdminWriter          writer        = null;
    protected ContainerResource    root          = null;
    protected RealmCatalogResource realmConfig   = null;
    protected ControlResource      controlConfig = null;
    protected GenericAuthFilter    auth          = null;

    /**
     * The realm catalog
     */
    private RealmsCatalog realms = null ;

    private void initializeRealmsCatalog() {
	this.realms = new RealmsCatalog(this, "adminRealms.db");
    }
    
    public RealmsCatalog getRealmsCatalog() {
	if(realms == null) {
	    initializeRealmsCatalog();
	}
	return realms;
    }

    protected String getBanner() {
	return "JigAdmin[1.0beta2]";
    }

    public ContainerResource getConfigResource() {
	return root;
    }

    public RealmCatalogResource getRealmCatalogResource() {
	if (realmConfig == null) {
	    realmConfig = new RealmCatalogResource(this);
	}
	return realmConfig;
    }

    public ControlResource getControlResource() {
	if (controlConfig == null) {
	    controlConfig = new ControlResource(this);
	}
	return controlConfig;
    }

    public Reply remoteLoadRoot(Request request) 
	throws HTTPException
    {
	// Dump the root resource:
	ByteArrayOutputStream bout = new ByteArrayOutputStream();
	DataOutputStream      out  = new DataOutputStream(bout);
	try {
	    writer.writeResource(out, root);
	    out.close();
	} catch (IOException ex) {
	    throw new HTTPException("unable to dump root");
	}
	byte bits[] = bout.toByteArray();
	// Setup the reply:
	Reply reply = request.makeReply(HTTP.OK);
	reply.setStream(new ByteArrayInputStream(bits));
	reply.setContentLength(bits.length);
	reply.setContentType(ResourceBroker.conftype);
	return reply;
    }

    public Reply remoteListAttributes(Request request) 
	throws HTTPException
    {
	// Get the name of the class whose attributes are being fetched:
	LookupState ls = new LookupState(request);
	String      cs = ls.getNextComponent();
	// Get this class attributes:
	Class c = null;
	try {
	    c = Class.forName(cs);
	} catch (Exception ex) {
	    ex.printStackTrace();
	    return null;
	}
	// Get the atributes:
	Attribute attrs[] = AttributeRegistry.getClassAttributes(c);
	byte      bits[]  = null;
	try {
	    // Dump them into a byte array:
	    ByteArrayOutputStream bout = new ByteArrayOutputStream();
	    DataOutputStream      out  = new DataOutputStream(bout);
	    writer.writeAttributes(out, attrs);
	    out.close();
	    bits = bout.toByteArray();
	} catch (Exception ex) {
	    ex.printStackTrace();
	    throw new HTTPException("couldn't dump attributes");
	}
	// Emit the appropriate HTP reply:
	Reply reply = request.makeReply(HTTP.OK);
	reply.setContentType(ResourceBroker.conftype);
	reply.setContentLength(bits.length);
	reply.setStream(new ByteArrayInputStream(bits));
	return reply;
    }

    public Reply perform(Request request) 
	throws HTTPException, ClientException
    {
	auth.authenticate(request);
	// Maybe that's one of the methods we handle straight ?
        String mth = request.getMethod();
	if ( mth.equals("LOAD-ROOT") ) {
	    return remoteLoadRoot(request);
	} else if (mth.equals("LIST-ATTRIBUTES")) {
	    return remoteListAttributes(request);
	}
	// Ok, that's targeted toward a specific target resource:
	return broker.perform(request);
    }

    public HTTPResource getRoot() {
	return root;
    }

    protected void initializeAuth() {
	Hashtable defs = null;
	defs = new Hashtable(3);
	defs.put("identifier", "auth-frame");
	root.registerFilter(auth, defs);
	auth.setValue("realm", "JigAdmin");
    }

    public void initialize(ServerHandlerManager shm
			   , String identifier
			   , ObservableProperties props)
	throws ServerHandlerInitException
    {
	super.initialize(shm, identifier, props);
	// Create our only resource:
	this.shm = shm;
	writer   = new AdminWriter(this);
	broker   = new ResourceBroker(shm, this, writer);
	root     = new ServerHandlerManagerResource(this, shm);
	auth     = new GenericAuthFilter();
	initializeAuth();
    }

    public AdminServer() {
    }
}
