package kr.util.sample;

import java.io.File;
import java.io.IOException;

import javax.management.Notification;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.sound.sampled.AudioFileFormat.Type;
import javax.sound.sampled.AudioFormat.Encoding;

import kr.util.Util;

import kr.util.NotificationManager;
import kr.util.audio.MemAudioClip;
import kr.util.audio.WritableAudioClip;

/**
 * Gets sound files of different types
 */
public class SoundRetrievalManager {
	public static void fillAudioClip(File sampleFile, WritableAudioClip audioOut)
			throws UnsupportedAudioFileException, IOException {
		
		long currTime = System.currentTimeMillis();
		
		AudioInputStream targetStream;
		
		int frameLength = -1;
		
		while(true)
		{
			AudioInputStream audioInputStream = AudioSystem
					.getAudioInputStream(sampleFile);
	
			AudioFormat intermediaryFormat = new AudioFormat(
					Encoding.PCM_SIGNED, (float) audioInputStream.getFormat()
							.getSampleRate(), 16, 2, 4,
							audioInputStream.getFormat()
							.getSampleRate(), false);
	
			AudioInputStream intermediary = AudioSystem.getAudioInputStream(
					intermediaryFormat, audioInputStream);
	
			AudioFormat targetFormat = new AudioFormat(Encoding.PCM_SIGNED,
					(float) audioOut.getRate(), audioOut.getSampleSizeInBits(),
					2,2 * audioOut.getSampleSizeInBits() / 8,
					(float) audioOut.getRate(), false);
	
			targetStream = AudioSystem.getAudioInputStream(
					targetFormat, intermediary);
			//targetStream = intermediary;
			
			
			System.out.println("target Format is " + targetFormat);
			
			if(frameLength == -1)
				frameLength = (int) audioInputStream.getFrameLength();
			
			if (frameLength == -1) {
				// find out the number of bytes by counting them in the output
				// stream
				frameLength = countBytes(targetStream) / audioOut.getNumChannels() * 8 / audioOut.getSampleSizeInBits();
				continue;
			}
			break;
		}

		System.out.println("frameLength is "+frameLength);
		
		audioOut.ensureCapacityInFrames(frameLength);

		byte[] data = new byte[65536];

		while (true) {
			int bytesRead = targetStream.read(data, 0, data.length / 4);
			if (bytesRead <= 0)
				break;

			audioOut.append(data, 0, bytesRead);

			NotificationManager.inst().progress(Math.min((double)audioOut.sizeInFrames() / frameLength ,1)
					, "Reading file");
		}
		
		NotificationManager.inst().finish();
		
		System.out.println("time passed in millis is "+(System.currentTimeMillis() - currTime));
	}

	private static int countBytes(AudioInputStream targetStream) throws IOException {
		long byteCount = 0;
		byte[] data = new byte[65536];
		while(true)
		{
			long bytesSkipped = targetStream.read(data, 0, data.length / 4);
			if(bytesSkipped > 0)
				byteCount += bytesSkipped;
			else
				break;
			
			NotificationManager.inst().progress(-1, "Determining file length");
			
			//System.out.println("byte count is "+byteCount);
		}
		
		NotificationManager.inst().finish();

		return (int) byteCount;
	}
}

class SoundRetrievalManagerTest {
	public static void main(String[] argv) throws Exception {
		MemAudioClip byteData = new MemAudioClip(2, 48000, 16);

		SoundRetrievalManager.fillAudioClip(new File(argv[0]), byteData);

		System.out.println("Mem Byte Data length is " + byteData.length());

		byte[] buf = new byte[1000];
		byteData.copyTo(0, 1000, buf, 0);
		System.out.println(Util.toHex(buf));

		// doesn't work
		// System.out.println("saving in KR format to "+argv[1]);
		//		
		// jmf.writeJMFData(byteData, new File(argv[1]));

	}

}
