/*
 * Written by Dawid Kurzyniec and released to the public domain, as explained
 * at http://creativecommons.org/licenses/publicdomain
 */

package edu.emory.mathcs.util.io;

import java.io.*;
import java.util.*;

/**
 * Output stream that multicasts its data to sevaral underlying output streams.
 *
 * @see TeeInputStream
 * @see RedirectingInputStream
 *
 * @author Dawid Kurzyniec
 * @version 1.0
 */
public class ForkOutputStream extends OutputStream {
    private final OutputStream[] outs;

    /**
     * Creates a new fork output stream multicasting to two specified streams.
     * @param out1 output #1
     * @param out2 output #2
     */
    public ForkOutputStream(OutputStream out1, OutputStream out2) {
        this(new OutputStream[] {out1, out2});
    }

    /**
     * Creates a new fork output stream multicasting to three specified streams.
     * @param out1 output #1
     * @param out2 output #2
     * @param out3 output #3
     */
    public ForkOutputStream(OutputStream out1, OutputStream out2, OutputStream out3) {
        this(new OutputStream[] {out1, out2, out3});
    }

    /**
     * Creates a new fork output stream multicasting to multiple specified
     * streams.
     * @param outs outputs to multicast to
     */
    public ForkOutputStream(OutputStream[] outs) {
        // remove duplicates and nulls, but maintain the order
        Set outset = new LinkedHashSet(Arrays.asList(outs));
        this.outs = (OutputStream[])outset.toArray(new OutputStream[outset.size()]);
    }

    public void write(byte[] buf) throws IOException {
        IOException ioe = null;
        for (int i = 0; i < outs.length; i++) {
            OutputStream out = outs[i];
            if (out == null) continue;
            try {
                out.write(buf);
            }
            catch (IOException e) {
                if (ioe == null) ioe = e;
            }
        }
        if (ioe != null) throw ioe;
    }

    public void write(byte[] buf, int off, int len) throws IOException {
        IOException ioe = null;
        for (int i = 0; i < outs.length; i++) {
            OutputStream out = outs[i];
            if (out == null) continue;
            try {
                out.write(buf, off, len);
            }
            catch (IOException e) {
                if (ioe == null) ioe = e;
            }
        }
        if (ioe != null) throw ioe;
    }

    public void write(int b) throws IOException {
        IOException ioe = null;
        for (int i = 0; i < outs.length; i++) {
            OutputStream out = outs[i];
            if (out == null) continue;
            try {
                out.write(b);
            }
            catch (IOException e) {
                if (ioe == null) ioe = e;
            }
        }
        if (ioe != null) throw ioe;
    }

    public void flush() throws IOException {
        IOException ioe = null;
        for (int i = 0; i < outs.length; i++) {
            OutputStream out = outs[i];
            if (out == null) continue;
            try {
                out.flush();
            }
            catch (IOException e) {
                if (ioe == null) ioe = e;
            }
        }
        if (ioe != null) throw ioe;
    }

    public void close() throws IOException {
        IOException ioe = null;
        for (int i = 0; i < outs.length; i++) {
            OutputStream out = outs[i];
            if (out == null) continue;
            try {
                out.close();
            }
            catch (IOException e) {
                if (ioe == null) ioe = e;
            }
        }
        if (ioe != null) throw ioe;
    }
}
