package org.yi.happy.archive.block;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;

import org.yi.happy.archive.ByteString;
import org.yi.happy.archive.Bytes;

/**
 * The part that is common for all the block types.
 */
public abstract class AbstractBlock implements Block {
    private byte[] ENDL = new byte[] { '\r', '\n' };
    private byte[] SEPARATOR = new byte[] { ':', ' ' };

    /**
     * get the block representation as bytes, assuming all the meta entries are
     * valid and the body is not null.
     */
    @Override
    public byte[] asBytes() {
	/*
	 * This can probably be done more efficiently, and maybe even more
	 * simply, without the stream.
	 */
	try {
	    ByteArrayOutputStream out = new ByteArrayOutputStream();

	    for (Map.Entry<String, String> i : getMeta().entrySet()) {
		out.write(ByteString.toUtf8(i.getKey()));
		out.write(SEPARATOR);
		out.write(ByteString.toUtf8(i.getValue()));
		out.write(ENDL);
	    }

	    out.write(ENDL);

	    out.write(getBody().toByteArray());

	    return out.toByteArray();
	} catch (IOException e) {
	    throw new Error(e);
	}
    }

    @Override
    public abstract Map<String, String> getMeta();

    @Override
    public abstract Bytes getBody();
}

@@ -34,74 +34,8 @@
 k;%0A%0A
-import java.io.ByteArrayOutputStream;%0Aimport java.io.IOException;%0A
 impo
@@ -538,191 +538,262 @@
  %7B%0A%09
-/*%0A%09 * This can probably be done more efficiently, and maybe even more%0A%09 * simply, without the stream.%0A%09 */%0A%09try %7B%0A%09    ByteArrayOutputStream out = new ByteArrayOutputStream();%0A%0A%09    
+Map%3CString, String%3E m = getMeta();%0A%09Bytes b = getBody();%0A%0A%09/*%0A%09 * calculate the size and gather the header bytes.%0A%09 */%0A%09byte%5B%5D%5B%5D p = new byte%5Bm.size() * 2%5D%5B%5D;%0A%09/**%0A%09 * index into the part list%0A%09 */%0A%09int i = 0;%0A%09/**%0A%09 * number of bytes.%0A%09 */%0A%09int n = 0;%0A%09
 for 
@@ -823,21 +823,13 @@
 ng%3E 
-i : getMeta()
+j : m
 .ent
@@ -840,27 +840,27 @@
 t()) %7B%0A%09
-%09out.write(
+    p%5Bi%5D = 
 ByteStri
@@ -865,25 +865,25 @@
 ring.toUtf8(
-i
+j
 .getKey()));
@@ -884,47 +884,83 @@
 y())
-)
 ;%0A%09
-%09out.write(SEPARATOR);%0A%09%09out.write(
+    n += p%5Bi%5D.length;%0A%09    n += SEPARATOR.length;%0A%09    i++;%0A%09    p%5Bi%5D = 
 Byte
@@ -973,17 +973,17 @@
 .toUtf8(
-i
+j
 .getValu
@@ -990,188 +990,664 @@
 e())
-)
 ;%0A%09
-%09out.write(ENDL);%0A%09    %7D%0A%0A%09    out.write(ENDL);%0A%0A%09    out.write(getBody().toByteArray());%0A%0A%09    return out.toByteArray();%0A%09%7D catch (IOException e) %7B%0A%09    throw new Error(e);%0A%09%7D
+    n += p%5Bi%5D.length;%0A%09    n += ENDL.length;%0A%09    i++;%0A%09%7D%0A%09n += ENDL.length;%0A%09n += b.getSize();%0A%0A%09/*%0A%09 * fill in the output.%0A%09 */%0A%09byte%5B%5D out = new byte%5Bn%5D;%0A%09n = 0;%0A%09for (i = 0; i %3C p.length; i += 2) %7B%0A%09    System.arraycopy(p%5Bi%5D, 0, out, n, p%5Bi%5D.length);%0A%09    n += p%5Bi%5D.length;%0A%09    System.arraycopy(SEPARATOR, 0, out, n, SEPARATOR.length);%0A%09    n += SEPARATOR.length;%0A%09    System.arraycopy(p%5Bi + 1%5D, 0, out, n, p%5Bi + 1%5D.length);%0A%09    n += p%5Bi + 1%5D.length;%0A%09    System.arraycopy(ENDL, 0, out, n, ENDL.length);%0A%09    n += ENDL.length;%0A%09%7D%0A%09System.arraycopy(ENDL, 0, out, n, ENDL.length);%0A%09n += ENDL.length;%0A%09b.getBytes(0, out, n, b.getSize());%0A%09return out;
 %0A   

write AbstractBlock.toByteArray() without using a stream to reduce copying, and make it look simpler.