// AdminReader.java 
// $Id: AdminReader.java,v 1.11 1998/12/08 10:13:01 bmahe 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.net.*;
import java.util.*;

import org.w3c.tools.resources.*;

class AdminReader implements AdminProtocol {
    /**
     * The RemoteResource factory to create remote resource instances.
     */
    RemoteResourceFactory factory = null;
    /**
     * The client side admin object we are attached to.
     */
    protected AdminContext admin = null;
    
    private RemoteResource readRawResource(URL parent,
					   String identifier,
					   DataInputStream in)
	throws IOException, AdminProtocolException
    {
	// Read the class hierarchy:
	Vector vector  = new Vector();
	int    clssz   = in.readInt();
	while (--clssz >= 0)
	    vector.addElement(in.readUTF());
	// And the identifier:
	String wireid = in.readUTF();
	wireid = (wireid.equals("")) ? null : wireid;
	String classes[] = new String[vector.size()];
	vector.copyInto(classes);
	if (identifier != null) {
	    // if ((wireid != null) && ! identifier.equals(wireid) )
	    // throw new RuntimeException("Implementation bug");
	    ;
	} else {
	    identifier = wireid;
	}
	// Create the RemoteResource with these infos:
	return factory.createRemoteResource(parent, identifier, classes);
    }
    
    private RemoteResource readRawResource(URL url,
					   DataInputStream in)
	throws IOException, AdminProtocolException
    {
	// Read the class hierarchy:
	Vector vector  = new Vector();
	int    clssz   = in.readInt();
	while (--clssz >= 0)
	    vector.addElement(in.readUTF());
	// And the resource identifier:
	String wireid = in.readUTF();
	String classes[] = new String[vector.size()];
	vector.copyInto(classes);
	// Create the RemoteResource with these infos:
	return factory.createRemoteResource(url, classes);
    }
    
    protected RemoteResource readFrame(URL frameUrl,
				       DataInputStream in)
	throws IOException, AdminProtocolException
    {
	int op = in.read();
	if (op != WIRED_FRAMED)
	    throw new AdminProtocolException("Invalid frame");
	int            nfr      = in.readInt();
	RemoteResource frames[] = null;
	if (nfr > 0) {
	    frames = new RemoteResource[nfr];
	    for (int i=0 ; i < nfr ; i++) {
		String frid = in.readUTF();
		URL    url  = null;
		try {
		    url = new URL(frameUrl.getProtocol(),
				  frameUrl.getHost(),
				  frameUrl.getPort(),
				  frameUrl.getFile()+"?"+ 
				  URLEncoder.encode(frid));
		    //url = new URL(frameUrl, frameUrl.getFile()+"?" + frid);
		} catch (MalformedURLException ex) {
		    ex.printStackTrace();
		}
		frames[i] = readFrame(url,in);
		((PlainRemoteResource) frames[i]).identifier = frid;
	    }
	}
	PlainRemoteResource r = null;
	r = (PlainRemoteResource) readRawResource(frameUrl,in);
	r.setFrames(frames);
	return r;
    }

    protected RemoteResource readResource(URL parent,
					  String identifier,
					  DataInputStream in)
	throws IOException, AdminProtocolException
    {
	int op = in.read();
	switch(op) {
        case WIRED_PLAIN:
	    return readRawResource(parent, identifier, in);
        case WIRED_FRAMED:
	    int            nfr      = in.readInt();
	    RemoteResource frames[] = null;
	    if (nfr > 0) {
		frames = new RemoteResource[nfr];
		for (int i=0 ; i < nfr ; i++) {
		    String frid = in.readUTF();
		    URL    url  = null;
		    try {
			String encoded = ((identifier == null) ? identifier :
					  URLEncoder.encode(identifier));
			String fridenc = ((frid == null) ? frid :
					  URLEncoder.encode(frid));
			url = new URL(parent.toExternalForm()+encoded+"?"+
				      fridenc);
		    } catch (MalformedURLException ex) {
			ex.printStackTrace();
		    }
		    frames[i] = readFrame(url, in);
		    //frames[i] = readRawResource(url, in);
		    ((PlainRemoteResource) frames[i]).identifier = frid;
		}
	    }
	    PlainRemoteResource r = null;
	    r = (PlainRemoteResource) readRawResource(parent,identifier,in);
	    r.setFrames(frames);
	    return r;
	default:
	    throw new RuntimeException("unknown opcode: "+op);
	}
    }

    protected Attribute[] readAttributes(DataInputStream in)
	throws IOException, AdminProtocolException
    {
	ObjectInputStream oin = new ObjectInputStream(in);
	try {
	    return (Attribute[]) oin.readObject();
	} catch (ClassNotFoundException ex) {
	    ex.printStackTrace();
	} catch (StreamCorruptedException ex) {
	    ex.printStackTrace();
	} catch (OptionalDataException ex) {
	    ex.printStackTrace();
	}
	throw new AdminProtocolException("Cannot restore attributes");
    }
    


    AdminReader(AdminContext admin) {
	this.admin   = admin;
	this.factory = new RemoteResourceFactory(admin);
    }
    
}


