/*
 * @(#)OutputReader.java
 *
 * Copyright (c) 2001-2002 JScape
 * 1147 S. 53rd Pl., Mesa, Arizona, 85206, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * JScape. ("Confidential Information").  You shall not disclose such
 * Confidential Information and shall use it only in accordance with
 * the terms of the license agreement you entered into with JScape.
 */
package com.jscape.inet.bsd;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;


/**
 * OutputReader is an utility class that should be is used to read the output
 * of a remote bsd process and write it to  local output stream.
 */
public class OutputReader
        extends Thread {
    private InputStream remoteOutput;
    private OutputStream localOutput;
    private Vector bsdListeners = null;
    private int bytesCount;
    private int singleByte;
    private byte[] buffer = new byte[1024];
    private long total = 0;

    /**
     * Constructs the OutputWriter thread.
     *
     * @param remoteOutput the <code>InputStream</code> stream that thread
     *                     reads from.
     * @param localOutput  the <code>OutputStream</code> stream that thread
     *                     writes to.
     * @param bsdListeners a <code>Vector</code> of <code>BsdListener</code>
     */
    public OutputReader(InputStream remoteOutput, OutputStream localOutput,
                        Vector bsdListeners) {
        this.remoteOutput = remoteOutput;
        this.localOutput = localOutput;
        this.bsdListeners = bsdListeners;
    }

    /**
     * Thread for controlling OutputReader.
     */
    public void run() {
        try {
            while ((bytesCount = remoteOutput.read(buffer)) != -1) {
                total += bytesCount;

                if (bytesCount == 0) {
                    singleByte = remoteOutput.read();

                    if (singleByte < 0) {
                        break;
                    }

                    ++total;
                    fireBytesReceived(total, 1);
                    localOutput.write(singleByte);
                    localOutput.flush();

                    continue;
                }

                fireBytesReceived(total, bytesCount);
                localOutput.write(buffer, 0, bytesCount);
                localOutput.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    /**
     * Fires <code>BsdBytesReceivedEvent</code>. This event is fired when data
     * is received from remote host.
     *
     * @param total the total number of bytes received thus far
     * @param bytes the total number of bytes in total
     *
     * @see BsdBytesReceivedEvent
     */
    protected void fireBytesReceived(long total, int bytes) {
        Vector thisList = new Vector();
        BsdBytesReceivedEvent thisEvent = new BsdBytesReceivedEvent(this,
                                                                    total, bytes);

        // Make a copy of the list so potential changes to it by
        // other threads won't affect traversal.
        synchronized (this) {
            thisList = (Vector) bsdListeners.clone();
        }

        // Send a BsdBytesReceivedEvent to every listener.
        for (int elem = 0; elem < thisList.size(); elem++) {
            ((BsdListener) thisList.elementAt(elem)).bytesReceived(thisEvent);
        }
    }
}
