/* ***************************************************************************+
 * ITX package (cnrg.itx) for telephony application programming.              *
 * Copyright (c) 1999  Cornell University, Ithaca NY                          *
 *                                                                            *
 * This program is free software; you can redistribute it and/or modify       *
 * it under the terms of the GNU General Public Liense as published by        *
 * the Free Software Foundation, either version 2 of the License, or (at      * 
 * your option) any later version.                                            *
 *                                                                            *
 * The ITX package 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.                                                          * 
 *                                                                            *
 * A copy of the license is distributed with this package.  Look in the docs  *
 * directory, filename GPL.                                                   *
 *                                                                            * 
 * Contact information:                                                       *
 * Donna Bergmark                                                             *
 * 484 Rhodes Hall                                                            *
 * Cornell University                                                         *
 * Ithaca, NY 14853-3801                                                      *
 * bergmark@cs.cornell.edu                                                    *
 ******************************************************************************/


package cnrg.itx.datax.jaudio;

public class JAudioBlock extends QueueElement
{
	//////////////////////////////////////////////////////////////////////
	//																	//
	//				 CLASS MEMBER VARIABLES								//
	//																	//
	//////////////////////////////////////////////////////////////////////

	// variable to run the JAudioBlock through a separate queue (for the purposes of 
	//  keeping track of free blocks.  NOTE: This is NOT used by jaudio. provided as a 
	//  convenience
	
	private JAudioBlock jabNext;

	// Audio data variables
	private byte data[];
	private int desiredLength;
	protected int wpHeader;
	private int wpData;

	// Marking and locking variables
	private boolean used, finished;
	private transient Object usedLock, finishedLock;

	//////////////////////////////////////////////////////////////////////
	//																	//
	//					  CLASS METHODS									//
	//																	//
	//////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////
	//
	//	JAudioBlock::JAudioBlock()
	//
	//	Description:
	//		Various JAudioDevice constructors.
	//	
	//	Parameters:
	//		See the various methods.
	//
	//	Returns:
	//		Nothing.
	//
	//	Throws:
	//		JAudioException
	//
	//////////////////////////////////////////////////////////////////////
	private JAudioBlock() 
	{
		jabNext = null;
		wpHeader = wpData = desiredLength = 0;
		data = null;
		used = finished = false;
		finishedLock = new Object();
		usedLock = new Object();
	}
	public JAudioBlock(byte data[]) throws JAudioException 
	{
		this();
		if (data == null || data.length == 0) 
		{
			throw new JAudioException("JAudioBlock must be non-null and positive length");
		}
		this.data = data;
	}
	public JAudioBlock(int newDesiredLength) throws JAudioException 
	{
		this();
		if (newDesiredLength <= 0) 
		{
			throw new JAudioException("JAudioBlock must have a positive length");
		}
		desiredLength = newDesiredLength;
	}

	//////////////////////////////////////////////////////////////////////
	//
	//	JAudioBlock::clone()
	//
	//	Description:
	//		Clones this instance of the JAudioBlock.
	//	
	//	Parameters:
	//		None.
	//
	//	Returns:
	//		A clone of this JAudioBlock.
	//
	//////////////////////////////////////////////////////////////////////
	public Object clone() 
	{
		JAudioBlock b = new JAudioBlock();
		b.data = data;
		b.desiredLength = desiredLength;
		return b;
	}

	//////////////////////////////////////////////////////////////////////
	//
	//	JAudioBlock::waitUntilFinished()
	//
	//	Description:
	//		Waits on the JAudioBlock until the current activity (playing
	//		or recording) is finished.
	//	
	//	Parameters:
	//		See the various methods.
	//
	//	Returns:
	//		Nothing.
	//
	//	Throws:
	//		InterruptedException
	//
	//////////////////////////////////////////////////////////////////////
	public void waitUntilFinished() throws InterruptedException 
	{
		if (finishedLock == null)
		{
			finishedLock = new Object();
		}
		synchronized (finishedLock) 
		{
			if (finished) 
			{
				return;
			}
			finishedLock.wait();
		}
	}

	//////////////////////////////////////////////////////////////////////
	//																	//
	//					  CLASS HELPER METHODS							//
	//																	//
	//////////////////////////////////////////////////////////////////////

	// All native methods
	private native void freeN();
	private native void copyDataN();

	// Accessors
	public byte[] getData()
	{
		return data;
	}

	public void setData(byte[] b)
	{
		data = b;
	}

	public void setNext(JAudioBlock jabNext)
	{
		this.jabNext = jabNext;
	}

	public JAudioBlock getNext()
	{
		return jabNext;
	}


	// Mark the buffer has "finished"
	protected void markAsFinished() 
	{
		if (finishedLock == null)
		{
			finishedLock = new Object();
		}
		synchronized (finishedLock) 
		{
			if (data == null) 
			{
				// Copy the data from wpData
				data = new byte[desiredLength];
				
			}
			copyDataN();

			// Free the DLL buffers
			freeN();
			finished = true;
			used = false;
			finishedLock.notifyAll();
		}
	}

	// Grab the "used" out lock
	protected boolean grabUsedOutLock() 
	{
		if (usedLock == null)
		{
			usedLock = new Object();
		}
		synchronized (usedLock) 
		{
			if (used || data == null) 
			{
				return false;
			}
			finished = false;
			used = true;
			return true;
		}
	}

	// Grab the "used" in lock
	protected boolean grabUsedInLock()
	{
		if (usedLock == null)
		{
			usedLock = new Object();
		}
		synchronized (usedLock) 
		{
			if (used) 
			{
				return false;
			}
			finished = false;
			used = true;
			return true;
		}
	}
}
