package com.jscape.inet.http.protocol.marshaling;

import com.jscape.inet.http.protocol.messages.Header;
import com.jscape.inet.http.protocol.messages.Headers;
import com.jscape.util.io.ByteArrayInputStream;

import java.io.IOException;
import java.io.InputStream;

import static com.jscape.util.Parameters.assertNotNull;

/**
 * @author Alex Usun
 */
public class ChunkDecodingInputStream
        extends InputStream {

    private final InputStream base;
    private final Headers trailerHeaders;
    private final ByteArrayInputStream readingBuffer;
    private boolean eofReached;

    public ChunkDecodingInputStream(InputStream base, Headers trailerHeaders) {
        assertNotNull(base);
        this.base = base;
        
        assertNotNull(trailerHeaders);
        this.trailerHeaders = trailerHeaders;

        this.readingBuffer = ByteArrayInputStream.empty();
    }

    @Override
    public int read()
            throws IOException {
        adjustBuffer();
        return this.readingBuffer.read();
    }

    @Override
    public int read(byte[] buffer, int offset, int length)
            throws IOException {
        adjustBuffer();
        return this.readingBuffer.read(buffer, offset, length);
    }

    private void adjustBuffer()
            throws IOException {
        if (this.readingBuffer.available() > 0 || this.eofReached) {
            return;
        }

        Chunk chunk = ChunkCodec.readValue(this.base);

        if (chunk != null) {
            this.readingBuffer.put(chunk.data, chunk.offset, chunk.length);
        } else {
            Header[] headers = HeadersCodec.readValue(this.base);
            for (Header header : headers) {
                this.trailerHeaders.add(header);
            }
            
            this.eofReached = true;
        }
    }
}
