package psemek.app;
import android.util.Log;
import android.content.res.AssetManager;
import android.media.AudioTrack;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import java.io.InputStream;
import java.io.IOException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.Arrays;
import java.lang.Thread;

public class PsemekApplication {

	private AudioTrack audioTrack;
	private Thread audioThread;
	private long nativeApp;

	private static native void setupLogging();
	private static native void setAssetManager(AssetManager assetManager);

	private static native long createNativeApp();
	private static native void destroyNativeApp(long ptr);
	private static native void resizeNative(long ptr, int width, int height);
	private static native void touchDownNative(long ptr, int x, int y);
	private static native void touchUpNative(long ptr, int x, int y);
	private static native void touchMoveNative(long ptr, int x, int y);
	private static native void drawFrameNative(long ptr);

	private static native int audioFrequencyNative();
	private static native int audioGetSamples(float buffer[], int sampleOffset, int sampleCount);

	private class StreamEventCallbackImpl extends AudioTrack.StreamEventCallback {

		private float buffer[];

		public StreamEventCallbackImpl() {
			super();
			buffer = new float[1024];
		}

		@Override
		public void onDataRequest(AudioTrack track, int sizeInFrames) {
			Log.e("psemek", "Requested audio " + sizeInFrames);
			int sizeInSamples = sizeInFrames * 2;
			if (buffer.length < sizeInSamples) {
				buffer = Arrays.copyOf(buffer, sizeInSamples);
			}

			int samples = PsemekApplication.audioGetSamples(buffer, 0, buffer.length);
			track.write(buffer, 0, samples, AudioTrack.WRITE_BLOCKING);
		}

	}

	private class AudioThreadImpl extends Thread {

		private float buffer[];

		public AudioThreadImpl(int bufferSizeInFrames) {
			super("audio");

			buffer = new float[bufferSizeInFrames * 2];
		}

		@Override
		public void run() {
			while (!interrupted()) {
				int samples = PsemekApplication.audioGetSamples(buffer, 0, buffer.length);
				PsemekApplication.this.audioTrack.write(buffer, 0, samples, AudioTrack.WRITE_BLOCKING);
				try {
					Thread.sleep(1);
				}
				catch (InterruptedException e) {
					break;
				}
			}
		}
	}

	public PsemekApplication(AssetManager assetManager) {
		setupLogging();
		setAssetManager(assetManager);

		AudioAttributes audioAttributes = new AudioAttributes.Builder()
			.setUsage(AudioAttributes.USAGE_GAME)
			.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
			.build();

		AudioFormat audioFormat = new AudioFormat.Builder()
			.setEncoding(AudioFormat.ENCODING_PCM_FLOAT)
			.setSampleRate(audioFrequencyNative())
			.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
			.build();

		int bufferSize = AudioTrack.getMinBufferSize(audioFrequencyNative(), AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_FLOAT);

		audioTrack = new AudioTrack.Builder()
			.setAudioAttributes(audioAttributes)
			.setAudioFormat(audioFormat)
			.setBufferSizeInBytes(bufferSize)
			.setTransferMode(AudioTrack.MODE_STREAM)
			.setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY)
			.build();

		audioThread = new AudioThreadImpl(audioTrack.getBufferCapacityInFrames());
		audioThread.start();

		audioTrack.play();
	}

	public void init() {
		nativeApp = createNativeApp();
	}

	public void resize(int width, int height) {
		resizeNative(nativeApp, width, height);
	}

	public void touchDown(int x, int y)
	{
		touchDownNative(nativeApp, x, y);
	}

	public void touchUp(int x, int y)
	{
		touchUpNative(nativeApp, x, y);
	}

	public void touchMove(int x, int y)
	{
		touchMoveNative(nativeApp, x, y);
	}

	public void drawFrame() {
		if (nativeApp != 0) {
			drawFrameNative(nativeApp);
		}
	}

	public void destroy() {
		audioThread.interrupt();
		if (nativeApp != 0)
			destroyNativeApp(nativeApp);
		nativeApp = 0;
	}

}
