/*
 *	MidiMessage.java
 *
 *	This file is part of Tritonus: http://www.tritonus.org/
 */

/*
 *  Copyright (c) 1999 - 2002 by Matthias Pfisterer
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library 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 Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
|<---            this code is formatted to fit into 80 columns             --->|
*/

package javax.sound.midi;

import org.tritonus.share.TDebug;
import org.tritonus.share.midi.MidiUtils;



/**	Base class for MIDI messages.

	@author Matthias Pfisterer
*/
public abstract class MidiMessage
implements Cloneable
{
	/**	The data of the message.
		This array contains the message separated into
		bytes.
		The storage format used for this array follows the way messages
		are sent via a MIDI cable or stored in a standard MIDI file.
		See the subclasses of MidiMessage to get more information on
		the required storage format for each type.<p>

		At any time after the execution of this class'
		constructor,
		this value must refer to an array with at least one element.
		Especially, <code>null</code> is not allowed.
		The array may contain more bytes than used to store the MIDI
		message. The variable {@link #length length} indicates the number
		of valid bytes. The content of the additional bytes has to be
		considered implementation-specific.<p>

		In this implementation, the length of data is always equal to the
		value of {@link #length length}. However, this is not a
		specification requirement.

		Accessing this member from subclasses is highly discouraged.
		Subclasses should use the constructor or
		{@link #setMessage(byte[], int) setMessage} to modify the content and
		{@link #getMessage() getMessage()} to retrieve it.

		@see #setMessage(byte[], int)
		@see #getMessage()
	 */
	protected byte[]		data;


	/**	The length of the message.
		This value represents the number of bytes in the array
		{@link #data data} that are valid.
		At any time after the execution of this class'
		constructor,
		this value is guaranteed to be
		greater or equal to one.
		Additinally,  with the exception of while the control flow is inside
		this class' method {@link #setMessage(byte[], int) setMessage()}
		the value is guaranteed to be as least as big as the length of
		{@link #data data}. It may be less than the length of
		{@link #data data} in cases where {@link #data data}
		contains additional (invalid) bytes.<p>

		Accessing this member from subclasses is highly discouraged.
		Subclasses should use the constructor or
		{@link #setMessage(byte[], int) setMessage()} to modify the length
		and
		{@link #getLength() getLength()} to retrieve it.

		@see #getLength()
	*/
	protected int			length;



	/** Constructs a MidiMessage.

	The passed array is used to initialize {@link #data data}.
	{@link #length length} is initialized to the length of the
	passed array. Note that a copy of the passed array is made.<p>

	This constructor does not use {@link #setMessage(byte[], int)
	setMessage()}. So it is unaffected by overriding setMessage().<p>

	It is unclear if the argument is allowed to be null. This
	implementation allows it, resulting in {@link #data data}
	being null, too.

	@param abData The data to use to construct the MIDI message.

	 */
	protected MidiMessage(byte[] abData)
	{
		if (abData != null)
		{
			copyToData(abData, abData.length);
		}
	}



	/**	Initializes the data of the message.
		This method sets the data of the MIDI message.
		<code>nLength</code> bytes of <code>abData</code> are copied to
		a newly created array, which is set as {@link #data data}.
		{@link #length length} is initialized to the value of
		<code>nLength</code>.<p>

		Open points: should we specify that this class'
		version of setMessage() (not the ones of derived
		classes) never throws an exception? Otherwise, we have
		to specify the cases where exceptions are thrown. For
		instance: abData == null, abData.length < nLength, ...

		@param abData The bytes to use as MIDI message. This array may
		contain trailing invalid bytes. <code>nLength</code> gives the
		number of valid bytes. This means that the length of
		<code>abData</code> has to be equal or greater than
		<code>nLength</code>.

		@param nLength The length of the MIDI message. This is equal to
		the number of valid bytes in <code>abData</code>. This value
		may be less than the length of <code>abData</code>. In this case,
		the remaining bytes have to be considered invalid. This means that
		the value of <code>nLength</code> has to be equal or less than
		the length of <code>abData</code>.
	 */
	protected void setMessage(byte[] abData, int nLength)
		throws InvalidMidiDataException
	{
		copyToData(abData, nLength);
	}



	/**
	   TODO:
	*/
	private void copyToData(byte[] abData, int nLength)
	{
		synchronized (this)
		{
			data = new byte[nLength];
			System.arraycopy(abData, 0, data, 0, nLength);
			length = nLength;
		}
	}



	/**	Return the complete message.
		This method makes a copy of {@link #data data} and returns a
		reference to the copy.
		The returned array contains only the bytes that form the MIDI
		message, even if {@link #data data} contains additional invalid
		bytes. This requirement also means that the length of the
		returned array is equal to {@link #length length} and equal
		to the value returned by {@link #getLength() getLength()}.

		@return An array of bytes representing the MIDI message.
	*/
	public byte[] getMessage()
	{
		byte[]	abData = new byte[length];
		System.arraycopy(data, 0, abData, 0, length);
		return abData;
	}



	/**	Returns the status byte of the message.
		This method returns the first byte of {@link #data data},
		which is always the status byte.

		@return The status byte of the MIDI message stored in this object.
	*/
	public int getStatus()
	{
		int	nStatus = MidiUtils.getUnsignedInteger(data[0]);
		return nStatus;
	}



	/**	Returns the length of the whole message in bytes.
		This returns the value of the member {@link #length length}.
		The value returned by this method
		is always equal to the length of the array returned by
		{@link #getMessage() getMessage()}.

		@return The length of the MIDI message in bytes.

		@see #length
		@see #getMessage()
	*/
	public int getLength()
	{
		return length;
	}


	/**	Create a copy of this MIDI message.
		@return A new MidiMessage object that is a copy of this one.
	*/
	public abstract Object clone();



	/**	Print content of data[].
		This method is used for debugging.
	*/
	private void outputData()
	{
		String	strMessage = "MidiMessage.outputData(): data: [";
		for (int i  = 0; i < data.length; i++)
		{
			strMessage += (data[i] + ", ");
		}
		strMessage += "]";
		TDebug.out(strMessage);
	}
}



/*** MidiMessage.java ***/
