// Copyright (C) 2002 Takeshi Morimoto <morimoto@takopen.cs.uec.ac.jp>
// All rights reserved.
package improvedYabAPI.io;

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

public class RCRSSProtocol implements ProtocolConstants {
    public static final byte[] body(Object[] elements) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        for (int i = 0;  i < elements.length;  i ++) {
            Object e = elements[i];
            if      (e instanceof Integer) writeIntElement(dos, e);
            else if (e instanceof int[])   writeIDsElement(dos, e);
            else if (e instanceof String)  writeStringElement(dos, e);
            else if (e instanceof byte[])  writeByteArrayElement(dos, e);
            else throw new Error("illegal element type:" + e);
        }
        byte[] body = baos.toByteArray();
        dos.close();
        baos.close();
        return body;
    }

    public static final void writeIntElement(DataOutputStream dos, Object e)
        throws IOException {
        int integer = ((Integer) e).intValue();
        dos.writeInt(integer);
    }

    public static final void writeIDsElement(DataOutputStream dos, Object e)
        throws IOException {
        int[] ids = (int[]) e;
        dos.writeInt(ids.length);
        for (int i = 0;  i < ids.length;  i ++)
            dos.writeInt(ids[i]);
//        dos.writeInt(0);
    }

    public static final void writeStringElement(DataOutputStream dos, Object e)
        throws IOException {
        byte[] str = ((String) e).getBytes();
        dos.writeInt(str.length);
        dos.write(str, 0, str.length);
//        int size = (str.length + 3) & ~3;
//        for (int i = str.length;  i <= size;  i ++)
//            dos.write(0);
    }

    public static final void writeByteArrayElement(DataOutputStream dos, Object e)
        throws IOException {
        byte[] str = (byte[])e;
        dos.writeInt(str.length);
        dos.write(str, 0, str.length);
//        int size = (str.length + 3) & ~3;
//        for (int i = str.length;  i <= size;  i ++)
//            dos.write(0);
    }

    public static final ObjectElement[] readObjectsElement(DataInputStream dis)
        throws IOException {
        List objs = new ArrayList();
        int type = dis.readInt();
        while (type != TYPE_NULL) {
            dis.readInt(); // length
            int id = dis.readInt();
            objs.add(new ObjectElement(type, id, readPropertiesElement(dis)));
            type = dis.readInt();
        }
        return (ObjectElement[]) objs.toArray(new ObjectElement[0]);
    }

    public static final PropertyElement[]
        readPropertiesElement(DataInputStream dis) throws IOException {
        List properties = new ArrayList();
        int type = dis.readInt();
        while (type != PROPERTY_NULL) {
            properties.add(new PropertyElement(type, propertyValue(type,dis)));
            type = dis.readInt();
        }
        return (PropertyElement[]) properties.toArray(new PropertyElement[0]);
    }

    private static final int[] propertyValue(int type, DataInputStream dis)
        throws IOException {
        int lenInByte = dis.readInt();
        if(lenInByte <= 4) return new int[] {dis.readInt()};
        return readListElement(dis);
    }

    private static final int readIntElement(DataInputStream dis)
        throws IOException {
        return dis.readInt();
    }

    private static final int[] readListElement(DataInputStream dis)
        throws IOException {
        int[] result = new int[dis.readInt()];
        for (int i = 0; i < result.length; i ++)
            result[i] = dis.readInt();
        return result;
    }

    private static final int[] m_buf = new int[1024];
    private static final int[] readIDsElement(DataInputStream dis)
        throws IOException {
        int i = -1;
        do {
            m_buf[++ i] = dis.readInt();
        } while (m_buf[i] != 0);
        int[] result = new int[i];
        System.arraycopy(m_buf, 0, result, 0, i);
        return result;
    }

    public static final String readStringElement(DataInputStream dis)
        throws IOException {
        byte[] buf = new byte[dis.readInt()];
        dis.read(buf, 0, buf.length);
//        int size = (buf.length + 3) & ~3;
//        dis.skip(size - buf.length); // See also the writeStringElement method
        return new String(buf);
    }

    public static final byte[] readByteArrayElement(DataInputStream dis)
        throws IOException {
        byte[] buf = new byte[dis.readInt()];
        dis.read(buf, 0, buf.length);
//        int size = (buf.length + 3) & ~3;
//        dis.skip(size - buf.length); // See also the writeStringElement method
        return buf;
    }
}
