/*
 * Copyright (c) 2004-2017, by Alex Leigh.
 * All rights reserved.
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
 * The copyright notice above does not evidence any
 * actual or intended publication of such source code.
 */

package lc.mecha.io;

import org.apache.commons.io.output.CountingOutputStream;

import java.io.*;


/**
 * This class implements a facility for simulating an object stream using RAM. It is useful to bridge the impedance
 * mismatch between actual streams and in-memory object arrays.
 *
 * @author Alex Leigh
 */
public final class StreamSimulator {
    final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
    final CountingOutputStream stream = new CountingOutputStream(byteStream);

    @Override
    public String toString() {
        return "StreamSimulator{" +
                "byteStream=" + byteStream +
                ", stream=" + stream +
                '}';
    }

    /**
     * Return the number of bytes which have been written into the stream.
     *
     * @return
     */
    public long getByteCount() {
        return stream.getByteCount();
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        final StreamSimulator that = (StreamSimulator) o;

        if (byteStream != null ? !byteStream.equals(that.byteStream) : that.byteStream != null) return false;
        return stream != null ? stream.equals(that.stream) : that.stream == null;

    }

    @Override
    public int hashCode() {
        int result = byteStream != null ? byteStream.hashCode() : 0;
        result = 31 * result + (stream != null ? stream.hashCode() : 0);
        return result;
    }

    public ObjectOutputStream getOutput() throws IOException {
        return new ObjectOutputStream(stream);
    }

    public void writeObjects(final Serializable... objects) throws IOException {
        final ObjectOutputStream oos = getOutput();
        for (final Serializable obj : objects) {
            oos.writeObject(obj);
        }
        oos.close();
    }

    /**
     * Write a single object to the stream. This method should not be called more than one
     * time on the same stream, or an <code>StreamCorruptedException</code> will result.
     *
     * @param object
     * @throws IOException
     */
    public void writeSingleObject(final Serializable object) throws IOException {
        writeObjects(object);
    }

    public ObjectInputStream getInput() throws IOException {
        return new ObjectInputStream(new ByteArrayInputStream(byteStream.toByteArray()));
    }
}
