package org.wikiwebserver.handler.http;

import java.io.IOException;
import java.io.OutputStream;

import org.wikiwebserver.core.ConfigManager;

public class ChunkedOutputStream extends OutputStream {
    
    private OutputStream out;
    
    private byte[] buffer = null;    
    private int ptr = 0;
    private long lastWrite = System.currentTimeMillis();
    private boolean finished = false;
    
    public ChunkedOutputStream(OutputStream out) {
        this.out = out;
    }

    public void write(int b) throws IOException {
        if (buffer == null) buffer = new byte[BUFFER_SIZE];
        
        buffer[ptr++] = (byte) b;
        
        // Is it time to write this chunk?
        long time = System.nanoTime();
        if (ptr == buffer.length || time - lastWrite > SMALL_WRITE_DELAY) {
            endChunk();
            lastWrite = time;            
        }
    }
    
    public void write(byte[] data) throws IOException {
        write(data, 0, data.length);
    }
    
    public void write(byte[] data, int off, int len) throws IOException {
        if (ptr > 0) endChunk();
        writeChunk(data, off, len);
    }
    
    public void close() throws IOException {
        finish();
        out.close(); 
    }
    
    public void flush() throws IOException {
        if (ptr > 0) endChunk();
        out.flush();
    }
    
    public void finish() throws IOException {
        if (!finished) {
            if (ptr > 0) endChunk();
            writeChunk(new byte[0], 0, 0);
            finished = true;
        }
    }
    
    
    private void endChunk() throws IOException {
        writeChunk(buffer, 0, ptr);
        ptr = 0;
    }    
    
    private void writeChunk(byte[] data, int off, int len) throws IOException {
        out.write((Integer.toString(len, 16) + LF).getBytes());
        out.write(data, off, len);
        out.write(LF.getBytes());
    }
    
    private static final int BUFFER_SIZE = 
    	ConfigManager.getInt("http.chunked-buffer-size");
    private static final long SMALL_WRITE_DELAY = 
    	ConfigManager.getLong("http.chunked-small-write-delay-ns");
    
    private static final String LF = "\r\n";    
}

