/*
@license.text@ 
 */

package com.hammurapi.common;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.concurrent.Callable;

/**
 * 
 * Copies all data from an input stream to an output stream.
 * @author Pavel Vlasov
 * @version $Revision: 1.3 $
 */
public class Pumper implements Callable<Long> {

    private final static int SIZE = 1024;
    private InputStream is;
    private OutputStream os;
    
    private boolean closeStreams=false;
	private Reader reader;
	private Writer writer;
    
    /**
     * Create a new pumper.
     *
     * @param is input stream to read data from
     * @param os output stream to write data to.
     */
    public Pumper(InputStream is, OutputStream os, boolean closeStreams) {
        this.is = is;
        this.os = os;
        this.closeStreams=closeStreams;
    }

    /**
     * Create a new pumper.
     *
     * @param reader Reader to read data from
     * @param writer Writer to write data to.
     */
    public Pumper(Reader reader, Writer writer, boolean closeStreams) {
        this.reader = reader;
        this.writer = writer;
        this.closeStreams=closeStreams;
    }

    /**
     * Copies data from the input stream to the output stream.
     * Terminates as soon as the input stream is closed or an error occurs.
     */
	public Long call() throws Exception {
		if (is==null) {
			return pump(reader, writer, closeStreams);
		}
		
		return pump(is, os, closeStreams);
    }

    /**
     * Copies data from the input stream to the output stream.
     */
    public static long pump(InputStream in, OutputStream out, boolean closeStreams) throws IOException {
    	try {
	        try {
	            final byte[] buf = new byte[SIZE];
	            int length;
	        	long ret = 0;
	            while ((length = in.read(buf)) != -1) {
	                out.write(buf, 0, length);
	                ret+=length;
	            }
	            return ret;
	        } finally {
	            if (closeStreams) {
	               in.close();
	            }
	        }
    	} finally {
            if (closeStreams) {
               out.close();
            }    		
    	}
    }

    /**
     * Copies data from the reader to the writer.
     */
    public static long pump(Reader in, Writer out, boolean closeStreams) throws IOException {
    	try {
	        try {
	            final char[] buf = new char[SIZE];
	            int length;
	        	long ret = 0;
	            while ((length = in.read(buf)) != -1) {
	                out.write(buf, 0, length);
	                ret+=length;
	            }
	            return ret;
	        } finally {
	            if (closeStreams) {
	               in.close();
	            }
	        }
    	} finally {
            if (closeStreams) {
               out.close();
            }    		
    	}
    }
	
}
