/*
 * Copyright 2010 Ning, Inc.
 *
 * Ning licenses this file to you under the Apache License, version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at:
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 */
package com.ning.http.client.generators;

import com.ning.http.client.Body;
import com.ning.http.client.BodyGenerator;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

/**
 * A {@link BodyGenerator} which use an {@link InputStream} for reading bytes, without having to read the entire
 * stream in memory.
 */
public class InputStreamBodyGenerator implements BodyGenerator {

    private final InputStream inputStream;
    private byte[] chunk;
    private boolean eof = false;

    public InputStreamBodyGenerator(InputStream inputStream) {
        this.inputStream = inputStream;
        inputStream.mark(0);
    }

    public Body createBody() throws IOException {
        return new ISBody();
    }

    protected class ISBody implements Body {

        public long getContentLength() {
            return -1;
        }

        public long read(ByteBuffer buffer) throws IOException {

            // To be safe.
            chunk = new byte[buffer.capacity() - 5];

            int read = inputStream.read(chunk);
            if (read == -1) {
                // Since we are chuncked, we must output extra bytes before considering the input stream closed.
                if (!eof) {
                    eof = true;
                    buffer.put("0".getBytes("UTF-8"));
                    buffer.put("\n".getBytes("UTF-8"));
                    return buffer.position();
                } else {
                    inputStream.reset();                    
                    eof = false;
                }
                return -1;
            }

            /**
             * Netty 3.2.3 doesn't support chunking encoding properly, so we chunk encoding ourself.
             */
            buffer.put(Integer.toHexString(read).getBytes("UTF-8"));
            buffer.put("\n".getBytes("UTF-8"));
            buffer.put(chunk, 0, read);
            return read;
        }

        public void close() throws IOException {
            inputStream.close();
        }
    }
}

@@ -732,16 +732,73 @@
 nerator;
+%0Aimport org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;
 %0A%0Aimport
@@ -1014,16 +1014,236 @@
 memory.%0A
+ *%0A * NOTE: The %7B@link InputStream%7D must support the %7B@link InputStream#mark%7D and %7B@link java.io.InputStream#reset()%7D operation.%0A * If not, mechanisms like authentication, redirect, or resumable download will not works.%0A
  */%0Apubl
@@ -1405,16 +1405,114 @@
 = false;
+%0A    private final static Logger logger = LoggerFactory.getLogger(InputStreamBodyGenerator.class);
 %0A%0A    pu
@@ -1612,36 +1612,211 @@
 am;%0A
-        inputStream.mark(0);
+%0A        if (inputStream.markSupported()) %7B%0A            inputStream.mark(0);%0A        %7D else %7B%0A            logger.warn(%22inputStream.markSupported() not supported. Some features will not works%22);%0A        %7D
 %0A   
@@ -2200,32 +2200,183 @@
 d = 
-inputStream.read(chunk);
+-1;%0A%0A            try %7B%0A                read = inputStream.read(chunk);%0A            %7D catch (IOException ex) %7B%0A                logger.warn(%22Unable to read%22, ex);%0A            %7D%0A
 %0A   

Improve robusness and javadoc