package w3c.jigsaw.upgrade.from1to2;

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

public class RawResourceUpgrader extends ResourceUpgrader {
    protected static String 
    HOLDER_ATTR = "w3c.tools.store.AttributeHolderAttribute";

    protected Class skipClass(DataInputStream in) 
	throws IOException
    {
	// First stage: class of the resource (stored as 1st item of ret) 
	String clsname = in.readUTF();
	try {
	    return Class.forName(clsname);
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return null;
    }

    protected Vector skipAttributeHolder(DataInputStream in) 
	throws IOException
    {
	Vector ret = new Vector(8);
	Class  cls = skipClass(in);
	ret.addElement(cls);
	if ( in.readBoolean() )
	    return null;
	skipAttributes(cls, in, ret);
	return ret;
    }

    protected Vector skipAttributes(Class cls, DataInputStream in, Vector ret)
	throws IOException
    {
	// Second stage: unpickle attributes (add to ret)
	w3c.tools.store.Attribute attrs[] = null;
	attrs = w3c.tools.store.AttributeRegistry.getClassAttributes(cls);
	// Slow pickle, skip bytes:
	String name = null;
	while ( ! (name = in.readUTF()).equals("") ) {
	    // This mimics AttributeHolder::lookupAttribute
	    w3c.tools.store.Attribute attr = null;
	    for (int i = 0 ; i < attrs.length; i++) {
		if ( name.equals(attrs[i].getName()) ) {
		    attr = attrs[i];
		    break;
		}
	    }
	    if (attr.getClass().getName().equals(HOLDER_ATTR)) {
		// Wow ! This is tricky, and severly hacked :-(
		try {
		    Class            c      = skipClass(in);
		    ResourceUpgrader up     = ResourceUpgrader.getUpgrader(c);
		    byte             bits[] = up.upgrade(c, in);
		    ret.addElement(new UpgradeAttributeHolderAttribute(attr
								       ,bits));
		} catch (ResourceUpgraderException ex) {
		    // That's really a nasty hack :-(
		    throw new IOException("Unable to restore attribute holder"
					  +" attribute.");
		}
	    } else {
		ret.addElement(new UpgradeAttribute(attr, attr.unpickle(in)));
	    }
	}
	return ret;
    }

    protected void pickleAttributes(Vector attrs, DataOutputStream out)
	throws IOException
    {
	int              sz = attrs.size();
	UpgradeAttribute ua = null;
	for (int i = 0 ; i < sz; i++) {
	    ua = (UpgradeAttribute) attrs.elementAt(i);
	    out.writeUTF(ua.attr.getName());
	    ua.pickle(out);
	}
	out.writeUTF("");
    }
    
    protected byte[] dump(Class cls, Vector attrs) {
	try {
	    ByteArrayOutputStream bout = new ByteArrayOutputStream(512);
	    DataOutputStream      out  = new DataOutputStream(bout);
	    dump(out, cls, attrs);
	    out.close();
	    return bout.toByteArray();
	} catch (Exception ex) {
	    ex.printStackTrace();
	    return null;
	}
    }

    protected void dump(DataOutputStream out, Class cls, Vector attrs) 
	throws IOException
    {
	// Dump the class (slow pickle) and std resource attrs:
	out.writeUTF(cls.getName());
	out.writeBoolean(false);
	pickleAttributes(attrs, out);
    }

    public byte[] upgrade(byte oldbits[], int off, int len) {
	Vector filters  = new Vector(8);
	Vector fattrs   = new Vector(8);
	Class  cls      = null;
	Vector rattrs   = null;

	// Read in the old format:
	try {
	    DataInputStream in     = (new DataInputStream
				      (new ByteArrayInputStream(oldbits
								, off
								, len)));
	    int                  oldlen = oldbits.length;
	    // Get the resource class and attributes
	    if ((rattrs = skipAttributeHolder(in)) == null)
		return null;
	    cls    = (Class) rattrs.elementAt(0);
	    rattrs.removeElementAt(0);
	} catch (Exception ex) {
	    ex.printStackTrace();
	    return null;
	}
	// Convert into the new format:
	return dump(cls, rattrs);
    }

    public byte[] upgrade(Class cls, DataInputStream in) {
	Vector attrs = new Vector(8);
	try {
	    if ( in.readBoolean() )
		return null;
	    skipAttributes(cls, in, attrs);
	} catch (IOException ex) {
	    ex.printStackTrace();
	    return null;
	}
	return dump(cls, attrs);
    }

}

