// AdminServer.java
// $Id: AdminServer.java,v 1.28 2000/03/06 10:07:30 ylafon Exp $
// (c) COPYRIGHT MIT and INRIA, 1997.
// Please first read the full copyright statement in file COPYRIGHT.html

package org.w3c.jigsaw.admin;

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

import org.w3c.util.*;

import org.w3c.tools.resources.*;
import org.w3c.www.mime.*;
import org.w3c.www.http.*;
import org.w3c.jigsaw.daemon.*;
import org.w3c.jigsaw.http.*;
import org.w3c.jigsaw.filters.TEFilter;
import org.w3c.jigsaw.auth.*;

import org.w3c.tools.resources.ProtocolException;
import org.w3c.tools.resources.ResourceException;
import org.w3c.tools.resources.serialization.Serializer;

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

    public ServerInterface getServer() {
	return as;
    }

    public ResourceReference 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 ResourceReference 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 AbstractContainer    root             = null;
    protected ResourceReference    rr_root          = null;
    protected ControlResource      controlConfig    = null;
    protected ResourceReference    rr_controlConfig = null;
    protected GenericAuthFilter    auth             = null;
    protected Serializer           serializer       = null;
    protected ResourceFilter       filters[]        = null;

    /**
     * The realm catalog
     */
  
    protected RealmsCatalog realms = null ;
    protected ResourceReference rr_realms = null;

    private void initializeRealmsCatalog() {
	this.realms = new RealmsCatalog(
	    new ResourceContext(getDefaultContext()),
	    "adminRealms.db");
    }
    
    public RealmsCatalog getRealmsCatalog() {
	if(realms == null) {
	    initializeRealmsCatalog();
	} 
	return realms;
    } 
  
    protected String getBanner() {
	return "JigAdmin[2.1.1]";
    } 

    public ResourceReference getConfigResource() {
	return getRootReference();
    }


    public ResourceReference getRealmCatalogResource() {
	if (rr_realms == null)
	    rr_realms = new DummyResourceReference(getRealmsCatalog());
	return rr_realms;
    }



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

    /**
     * Load the remote Root.
     * @param request The incomming request.
     * @exception org.w3c.tools.resources.ProtocolException if a protocol 
     * error occurs.
     */
    public Reply remoteLoadRoot(Request request) 
	throws ProtocolException
    {
	// Dump the root resource:
	ByteArrayOutputStream bout = new ByteArrayOutputStream();
	try {
	    writer.writeResource(root, bout);
	} catch (IOException ex) {
	    System.out.println(ex.getMessage());
	    ex.printStackTrace();
	    throw new HTTPException("unable to dump root");
	} catch (Exception ex) {
	    System.out.println(ex.getMessage());
	    ex.printStackTrace();
	    throw new HTTPException("unable to dump root: "+ex.getMessage());
	}
	byte bits[] = bout.toByteArray();
	// Setup the reply:
	Reply reply = request.makeReply(HTTP.OK);
	reply.setStream(new ByteArrayInputStream(bits));
	reply.setContentLength(bits.length);
	reply.setContentType(AdminContext.conftype);
	return reply;
    }

    /**
     * Perform the request
     * @param req the request.
     * @exception ProtocolException if a protocol error occurs
     * @exception ResourceException if a server error occurs
     */
    public ReplyInterface perform(RequestInterface req) 
	throws ProtocolException, ResourceException
    {
	Request request = (Request) req;
	Reply   reply   = null;
	auth.authenticate(request);
	//ingoing filters
	for (int i = 0 ; i < filters.length ; i++) {
	    reply = (Reply) filters[i].ingoingFilter(req);
	    if (reply != null)
		return reply;
	}
	// Maybe that's one of the methods we handle straight ?
	String mth = request.getMethod();
	if ( mth.equals("LOAD-ROOT") ) {
	    reply = remoteLoadRoot(request);
	} else {
	    // Ok, that's targeted toward a specific target resource:
	    try {
		reply = (Reply)broker.perform(request);
	    } catch (org.w3c.tools.resources.ProtocolException ex) {
		throw new HTTPException(ex);
	    }
	}
	//outgoing filters
	for (int i = filters.length-1 ; i > -1 ; i--) {
	    Reply rep = (Reply) filters[i].outgoingFilter(req, reply);
	    if (rep != null)
		return rep;
	}
	return reply;
    }
    
    public FramedResource getRoot() {
	return root;
    }

    public ResourceReference getRootReference() {
	if (rr_root == null)
	    rr_root = new DummyResourceReference( root );
	return rr_root;
    }

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

    protected void addFilter(ResourceFilter filter, Hashtable defs) {
	filter.initialize(defs);
	if (filters == null) {
	    filters = new ResourceFilter[1];
	    filters[0] = filter;
	} else {
	    int len = filters.length;
	    ResourceFilter nfilters[] = new ResourceFilter[len+1];
	    System.arraycopy(filters, 0, nfilters, 0, len);
	    nfilters[len] = filter;
	    filters = nfilters;
	}
    }

    /**
     * Initialize the Server
     * @exception ServerHandlerInitException if it can't be initialized
     */
    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();
	broker     = new ResourceBroker(shm, this, writer);
	root       = new ServerHandlerManagerResource(this, shm);
	auth       = new GenericAuthFilter();
	serializer = 
	    new org.w3c.tools.resources.serialization.xml.XMLSerializer();
	initializeAuth();
	TEFilter tefilter = new TEFilter();
	Hashtable defs = new Hashtable(2);
	defs.put("identifier", "tefilter");
	String mimes[] = { AdminContext.conftype.toString() };
	defs.put("mime-types", mimes );
	addFilter(tefilter, defs);
    }

    public AdminServer() {
    }
}
