/**
 * Copies data from InputStream (Source) to OutputStream (Target),
 * in a new thread..
 * 
 * IT has 2 modes:
 * 1. endlessly until you say stop().
 *    If the stream ends by itself (before you say stop), it's considered an error.
 *    E.g. for a TV Card as Source
 * 2. until the end of the stream
 *    The stream end is expected and normal.
 *    E.g. for a file as Source
 */
package org.bucksch.zeipis.store;
import org.bucksch.zeipis.all.Util;
import java.io.*;

public class StreamCopy
{
  public void copy(final Source source, final Target target, final boolean endless, final String name)
    throws Exception
  {
    final InputStream in = new BufferedInputStream(source.inStream());
    final OutputStream out = new BufferedOutputStream(target.outStream());
    Util.debug("Starting " + name + " from " + source + " to " + target);
    copy(in, out, endless, name);
  }
  public void copy(final InputStream in, final OutputStream out, final boolean endless, final String name)
    throws Exception
  {
    myStopSignal = false;
    Thread t = new Thread(name)
    {
      @Override
      public void run()
      {
        //Util.debug("Starting " + name);
        try
        {
          copyBlocking(in, out, endless);
        } catch (Exception e) {
          Util.error(e); // XXX pass to consumer
          e.printStackTrace();
        }
      }
    };
    t.start();
  }
  public void copyBlocking(InputStream in, OutputStream out, boolean endless)
    throws IOException
  {
    try {
      int count;
      byte[] buffer = new byte[1024];
      while ( ! myStopSignal)
      {
        count = in.read(buffer); // blocks until input data is available or EOF
        if (count == -1) // EOF
        {
          if (endless)
            throw new StreamBroke();
          else
            break;
        }
        out.write(buffer, 0, count);
        Thread.yield();
      }
      //Util.debug("streamcopy received stop signal");
    } finally {
      in.close();
      out.close();
      myIsClosed = true;
    }
  }
  /**
   * Called from other threads
   * XXX Blocks until the recording is stopped
   * @throws IOException 
   */
  public void stop()
  {
    //Util.debug("streamcopy stop signal");
    myStopSignal = true;
    while ( ! myIsClosed) // TODO synchronized?
      Thread.yield();
    //Util.debug("streamcopy stopped");
  }

  // Data
  // must be thread-safe
  protected boolean myStopSignal = false;
  protected boolean myIsClosed = false;
}



class StreamBroke extends IOException
{
  private static final long serialVersionUID = -2495734906531400088L;
  public StreamBroke()
  {
    super("Stream broke in the middle"); // TODO localize
  }
}
