package kompose;

import javax.sound.midi.*;

class DumpReceiver implements Receiver {
	long seByteCount = 0;

	long seCount = 0;

	long smCount = 0;

	String[] sm_astrKeyNames = { "C", "C#", "D", "D#", "E",
			"F", "F#", "G", "G#", "A", "A#", "B" };

	String[] sm_astrKeySignatures = { "Cb", "Gb", "Db",
			"Ab", "Eb", "Bb", "F", "C", "G", "D", "A", "E",
			"B", "F#", "C#" };

	String[] SYSTEM_MESSAGE_TEXT = {
			"System Exclusive (should not be in ShortMessage!)",
			"MTC Quarter Frame: ",
			"Song Position: ",
			"Song Select: ",
			"Undefined",
			"Undefined",
			"Tune Request",
			"End of SysEx (should not be in ShortMessage!)",
			"Timing clock", "Undefined", "Start",
			"Continue", "Stop", "Undefined",
			"Active Sensing", "System Reset" };

	String[] QUARTER_FRAME_MESSAGE_TEXT = {
			"frame count LS: ", "frame count MS: ",
			"seconds count LS: ", "seconds count MS: ",
			"minutes count LS: ", "minutes count MS: ",
			"hours count LS: ", "hours count MS: " };

	String[] FRAME_TYPE_TEXT = { "24 frames/second",
			"25 frames/second", "30 frames/second (drop)",
			"30 frames/second (non-drop)", };
			

	public String decodeMessage(ShortMessage event) {
		String strMessage = null;
		switch (event.getCommand()) {
		case 0x80:
			strMessage = "event "
					+ event.getStatus() + " " + event.getData1()
					+ " " + event.getData2();
			break;

		case 0x90:
			strMessage = "event "
					+ event.getStatus() + " " + event.getData1()
					+ " " + event.getData2();
			break;

		case 0xa0:
			strMessage = "event "
					+ event.getStatus() + " " + event.getData1()
					+ " " + event.getData2();
			break;

		case 0xb0:
			strMessage = "event "
					+ event.getStatus() + " " + event.getData1()
					+ " " + event.getData2();
			break;

		case 0xc0:
			strMessage = "event "
					+ event.getStatus() + " " + event.getData1();
			break;

		case 0xd0:
			strMessage = "event "
					+ event.getStatus() + " " + event.getData1()
					+ " " + event.getData2();
			break;

		case 0xe0:
			strMessage = "event "
					+ event.getStatus() + " " + get14bitValue(event.getData1(), event
							.getData2());
			break;

		case 0xF0:
			strMessage = SYSTEM_MESSAGE_TEXT[event
					.getChannel()];
			switch (event.getChannel()) {
			case 0x1:
				int nQType = (event.getData1() & 0x70) >> 4;
				int nQData = event.getData1() & 0x0F;
				if (nQType == 7) {
					nQData = nQData & 0x1;
				}
				strMessage += QUARTER_FRAME_MESSAGE_TEXT[nQType]
						+ nQData;
				if (nQType == 7) {
					int nFrameType = (event.getData1() & 0x06) >> 1;
					strMessage += ", frame type: "
							+ FRAME_TYPE_TEXT[nFrameType];
				}
				break;

			case 0x2:
				strMessage += get14bitValue(event
						.getData1(), event.getData2());
				break;

			case 0x3:
				strMessage += event.getData1();
				break;
			}
			break;

		default:
			strMessage = "unknown message: status = "
					+ event.getStatus() + ", byte1 = "
					+ event.getData1() + ", byte2 = "
					+ event.getData2();
			break;
		}
		
		smCount++;
		return  strMessage;
	}

	public String decodeMessage(SysexMessage event) {
		byte[] abData = event.getData();
		String strMessage = null;
		// System.out.println("sysex status: " + event.getStatus());
		if (event.getStatus() == SysexMessage.SYSTEM_EXCLUSIVE) {
			strMessage = "Sysex message: F0"
					+ getHexString(abData);
		} else if (event.getStatus() == SysexMessage.SPECIAL_SYSTEM_EXCLUSIVE) {
			strMessage = "Continued Sysex message F7"
					+ getHexString(abData);
			seByteCount--; // do not count the F7
		}
		seByteCount += abData.length + 1;
		seCount++; // for the status byte
		return strMessage;
	}

	public String decodeMessage(MetaMessage event) {
		byte[] abMessage = event.getMessage();
		byte[] abData = event.getData();
		int nDataLength = event.getLength();
		String strMessage = null;
		// System.out.println("data array length: " + abData.length);
		switch (event.getType()) {
		case 0:
			int nSequenceNumber = ((abData[0] & 0xFF) << 8)
					| (abData[1] & 0xFF);
			strMessage = "Sequence "
					+ nSequenceNumber;
			break;

		case 1:
			String strText = new String(abData);
			strMessage = "Text " + strText;
			break;

		case 2:
			String strCopyrightText = new String(abData);
			strMessage = "Copyright "
					+ strCopyrightText;
			break;
/*  --- original ------

		case 3:
			String strTrackName = new String(abData);
			strMessage = "Name "
					+ strTrackName;
			break;
*/
		case 3:
			String strTrackName = new String(abData);
			strMessage = "Name "
					+ strTrackName;
			break;

/*  --- original -----

		case 4:
			String strInstrumentName = new String(abData);
			strMessage = "Instrument "
					+ strInstrumentName;
			break;
*/

		case 4:
			String strInstrumentName = new String(abData);
			strMessage = ""
					+ strInstrumentName;
			break;

		case 5:
			String strLyrics = new String(abData);
			strMessage = "Lyric " + strLyrics;
			break;

		case 6:
			String strMarkerText = new String(abData);
			strMessage = "Marker " + strMarkerText;
			break;

		case 7:
			String strCuePointText = new String(abData);
			strMessage = "Cue " + strCuePointText;
			break;

		case 0x20:
			int nChannelPrefix = abData[0] & 0xFF;
			strMessage = "MIDI_Ch_Prefix "
					+ nChannelPrefix;
			break;

		case 0x2F:
			strMessage = "End";
			break;

		case 0x51:
			int nTempo = ((abData[0] & 0xFF) << 16)
					| ((abData[1] & 0xFF) << 8)
					| (abData[2] & 0xFF); // tempo in microseconds per beat
			float bpm = convertTempo(nTempo);
			// truncate it to 2 digits after dot
			bpm = (int) (Math.round(bpm * 100.0f) / 100.0f);
			strMessage = "Tempo " + bpm;
			break;

		case 0x54:
			// System.out.println("data array length: " + abData.length);
			strMessage = "SMTPE_Offset "
					+ (abData[0] & 0xFF) + ":"
					+ (abData[1] & 0xFF) + ":"
					+ (abData[2] & 0xFF) + "."
					+ (abData[3] & 0xFF) + "."
					+ (abData[4] & 0xFF);
			break;

		case 0x58:
			strMessage = "Time_Signature "
					+ (abData[0] & 0xFF) + "/"
					+ (1 << (abData[1] & 0xFF))
					+ " clocks_per_tick "
					+ (abData[2] & 0xFF)
					+ " 1/32_per_24_clocks "
					+ (abData[3] & 0xFF);
			break;

		case 0x59:
			String strGender = (abData[1] == 1) ? "minor"
					: "major";
			strMessage = "Key "
					+ sm_astrKeySignatures[abData[0] + 7]
					+ " " + strGender;
			break;

		case 0x7F:
			// TODO: decode vendor code, dump data in rows
			String strDataDump = getHexString(abData);
			strMessage = "Sequencer_Meta-event "
					+ strDataDump;
			break;

		default:
			String strUnknownDump = getHexString(abData);
			strMessage = "unknown_Meta-event "
					+ strUnknownDump;
			break;

		}
		return strMessage;
	}


	public String getKeyName(int nKeyNumber) {
		if (nKeyNumber > 127) {
			return "illegal value";
		} else {
			int nNote = nKeyNumber % 12;
			int nOctave = nKeyNumber / 12;
			return sm_astrKeyNames[nNote] + (nOctave - 1);
		}
	}

	public int get14bitValue(int nLowerPart, int nHigherPart) {
		return (nLowerPart & 0x7F)
				| ((nHigherPart & 0x7F) << 7);
	}

	private int signedByteToUnsigned(byte b) {
		return b & 0xFF;
	}

	// convert from microseconds per quarter note to beats per minute and vice versa
	private float convertTempo(float value) {
		if (value <= 0) {
			value = 0.1f;
		}
		return 60000000.0f / value;
	}

	private char hexDigits[] = { '0', '1', '2', '3', '4',
			'5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
			'E', 'F' };

	public String getHexString(byte[] aByte) {
		StringBuffer sbuf = new StringBuffer(
				aByte.length * 3 + 2);
		for (int i = 0; i < aByte.length; i++) {
			sbuf.append(' ');
			sbuf.append(hexDigits[(aByte[i] & 0xF0) >> 4]);
			sbuf.append(hexDigits[aByte[i] & 0x0F]);
			/*byte  bhigh = (byte) ((aByte[i] &  0xf0) >> 4);
			 sbuf.append((char) (bhigh > 9 ? bhigh + 'A' - 10: bhigh + '0'));
			 byte    blow = (byte) (aByte[i] & 0x0f);
			 sbuf.append((char) (blow > 9 ? blow + 'A' - 10: blow + '0'));*/
		}
		return new String(sbuf);
	}

	private String intToHex(int i) {
		return "" + hexDigits[(i & 0xF0) >> 4]
				+ hexDigits[i & 0x0F];
	}

	public String getHexString(ShortMessage sm) {
		// bug in J2SDK 1.4.1
		// return getHexString(sm.getMessage());
		int status = sm.getStatus();
		String res = intToHex(sm.getStatus());
		// if one-byte message, return
		switch (status) {
		case 0xF6: // Tune Request
		case 0xF7: // EOX
		// System real-time messages
		case 0xF8: // Timing Clock
		case 0xF9: // Undefined
		case 0xFA: // Start
		case 0xFB: // Continue
		case 0xFC: // Stop
		case 0xFD: // Undefined
		case 0xFE: // Active Sensing
		case 0xFF:
			return res;
		}
		res += ' ' + intToHex(sm.getData1());
		// if 2-byte message, return
		switch (status) {
		case 0xF1: // MTC Quarter Frame
		case 0xF3: // Song Select
			return res;
		}
		switch (sm.getCommand()) {
		case 0xC0:
		case 0xD0:
			return res;
		}
		// 3-byte messages left
		res += ' ' + intToHex(sm.getData2());
		return res;
	}

	/* (non-Javadoc)
	 * @see javax.sound.midi.Receiver#send(javax.sound.midi.MidiMessage, long)
	 */
	public void send(MidiMessage arg0, long arg1) {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see javax.sound.midi.Receiver#close()
	 */
	public void close() {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see javax.sound.midi.Receiver#send(javax.sound.midi.MidiMessage, long)
	 */

}



















