
/**
 * JMichelle (Java Midori Shell)
 * Copyright (C) 2000 Midori IGA 
 *   (http://www01.u-page.so-net.ne.jp/db3/midori/midosoft.html)
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

package jp.ne.nifty.iga.midori.shell.io;

import java.io.*;

/**
 * JMichelle (Java Midori Shell) : Stream connect thread.
 */
public class MdShellStreamConnectThread
	extends Thread
{
	private static final int DEFAULT_BUFFER_SIZE=1024;

	private InputStream inStream=null;
	private OutputStream outStream=null;
	private int iResetSize=DEFAULT_BUFFER_SIZE;

	private boolean isClosing=false;

	public MdShellStreamConnectThread(InputStream inStream,OutputStream outStream,int iResetSize)
	{
		this.inStream=inStream;
		this.outStream=outStream;
		this.iResetSize=iResetSize;
	}

	public MdShellStreamConnectThread(InputStream inStream,OutputStream outStream)
	{
		this(inStream,outStream,DEFAULT_BUFFER_SIZE);
	}

	public void run()
	{
		byte[] byteBuf=new byte[iResetSize];
		for(;;)
		{
			// yield() results stdout stderr confliction.
			// Thread.yield();

			if(isClosing)
			{
				break;
			}

			// It is the point where is very important that synchronize here.
			synchronized(inStream)
			{
				if(copyTransaction(byteBuf))
				{
					return;
				}
			}
		}
	}

	/**
	 * The stop of thread. But, it goes well at present, and it is'nt.
	 */
	public void close()
	{
		isClosing=true;

		// This isn't effective in the block condition of read().
		interrupt();
	}

	/**
	 * please syncronize input stream before this method call.
	 * @return true:treminating
	 */
	private boolean copyTransaction(byte[] byteBuf)
	{
		beginTransactionStream();

		int iRet=(-1);
		try{
			iRet=inStream.read(byteBuf);
			if(iRet<0)
			{
				return true;
			}
		}catch(IOException ex){
			//System.out.println("Input stream is blocked.: "+ex.toString());
			return true;
		}

		if(isClosing)
		{
			rollbackTransactionStream();
			return true;
		}

		try{
			outStream.write(byteBuf,0,iRet);
			outStream.flush();
		}catch(IOException ex){
			rollbackTransactionStream();
			return true;
		}

		return false;
	}

	/**
	 * begin input stream transaction.
	 */
	private void beginTransactionStream()
	{
		inStream.mark(iResetSize);
	}

	/**
	 * rollback input stream transaction.
	 */
	private void rollbackTransactionStream()
	{
		try
		{
			inStream.reset();
		}catch(IOException ex2){
			System.out.println(ex2.toString());
			ex2.printStackTrace();
		}
	}
}



