/*
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
 * language governing rights and limitations under the License.
 * 
 * The Original Code is the Venice Web Communities System.
 * 
 * The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
 * for Silverwrist Design Studios.  Portions created by Eric J. Bowersox are
 * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.util;

import java.io.*;

public class CacheInputStream extends FilterInputStream
{
  /*---------------------------------------------------------------------------
   * Static data members
   *---------------------------------------------------------------------------
   */

  private static final int MAX_MEMORY = 65536;

  /*---------------------------------------------------------------------------
   * Attributes
   *---------------------------------------------------------------------------
   */

  private File m_tempfile = null;
  private int m_length = 0;

  /*---------------------------------------------------------------------------
   * Constructor
   *---------------------------------------------------------------------------
   */

  public CacheInputStream(String temp_prefix, InputStream data) throws IOException
  {
    super(new ByteArrayInputStream(new byte[0]));  // dummy value

    boolean complete = false;
    OutputStream imstm = null;
    try
    { // Copy data to a temporary stream.
      ByteArrayOutputStream imstm_byte = new ByteArrayOutputStream();
      imstm = imstm_byte;
      byte[] buf = new byte[4096];
      int rd = data.read(buf);
      while (rd>=0)
      { // a simple copy loop, but with a twist
	if (rd>0)
	{ // if we go over memory limits, we'll have to create a tempfile
	  // and spill there...
	  if ((imstm_byte!=null) && ((rd + m_length)>MAX_MEMORY))
	  { // get the source for the copy
	    ByteArrayInputStream copy_src =
	        new ByteArrayInputStream(imstm_byte.toByteArray());

	    // get the destination for the copy
	    m_tempfile = File.createTempFile(temp_prefix,null);
	    imstm = new FileOutputStream(m_tempfile);

	    // copy it and close the byte stream
	    IOUtils.copy(copy_src,imstm);
	    IOUtils.shutdown(copy_src);
	    IOUtils.shutdown(imstm_byte);
	    imstm_byte = null;
	  
	  } // end if

	  // write data to the intermediate stream
	  imstm.write(buf,0,rd);
	  m_length += rd;

	} // end if

	rd = data.read(buf);

      } // end while

      if (imstm_byte!=null)
	this.in = new ByteArrayInputStream(imstm_byte.toByteArray());
      else
      { // close the file output stream, create a file input stream
	IOUtils.shutdown(imstm);
	imstm = null;
	this.in = new FileInputStream(m_tempfile);

      } // end else

      complete = true;

    } // end try
    finally
    { // close down the intermediate stream
      IOUtils.shutdown(imstm);
      if (!complete && (m_tempfile!=null))
      { // delete the temporary file
	m_tempfile.delete();
	m_tempfile = null;

      } // end if

    } // end finally

  } // end constructor

  /*---------------------------------------------------------------------------
   * Overrides from class FilterInputStream
   *---------------------------------------------------------------------------
   */

  public void close() throws IOException
  {
    try
    { // call through and close the stream
      super.close();

    } // end try
    finally
    { // delete the temp file as well
      if (m_tempfile!=null)
	m_tempfile.delete();
      m_tempfile = null;

    } // end finally

  } // end close

  /*---------------------------------------------------------------------------
   * External operations
   *---------------------------------------------------------------------------
   */

  int getLength()
  {
    return m_length;

  } // end getLength

} // end class CacheInputStream
