package zero1hd.polyjet.audio;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;

import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.TagException;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.files.FileHandle;

public class Mp3AudioData implements AudioData {
	private int readWindowSize = 1024;

	private AudioInputStream din;

	private AudioFormat decodedFormat;
	private Music playbackMusic;
	private int readIndex;

	private int sampleCount;

	private AudioInputStream in;

	public Mp3AudioData(FileHandle audioFile) {
		try {
			sampleCount = (int) new MP3File(audioFile.file()).getMP3AudioHeader().getNumberOfFrames();
		} catch (IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e1) {
			e1.printStackTrace();
		}

		reset();

		try {
			File file = audioFile.file();
			in = AudioSystem.getAudioInputStream(file);
			din = null;
			AudioFormat baseFormat = in.getFormat();
			decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16,
					baseFormat.getChannels(), baseFormat.getChannels() * 2, baseFormat.getSampleRate(), false);
			din = AudioSystem.getAudioInputStream(decodedFormat, in);
		} catch (UnsupportedAudioFileException | IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		playbackMusic = Gdx.audio.newMusic(audioFile);
	}

	@Override
	public void readIndexUpdate() {
		readIndex = (int) (playbackMusic.getPosition() * decodedFormat.getSampleRate() / readWindowSize);
	}

	@Override
	public int getReadIndex() {
		return readIndex;
	}

	@Override
	public void reset() {
		if (playbackMusic != null) {
			playbackMusic.stop();
			playbackMusic.dispose();
			playbackMusic = null;
		}

		if (din != null) {
			try {
				din.close();
				in.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	@Override
	public int getReadWindowSize() {
		return readWindowSize;
	}

	@Override
	public Music getPlaybackMusic() {
		return playbackMusic;
	}

	byte[] toBeConverted = new byte[2];

	@Override
	public int readSamples(float[] samples) {
		int samplesRead = 0;
		short sampleAverage = 0;
		

		for (int currentSample = 0; currentSample < samples.length; currentSample++) {
			for (int channel = 0; channel < decodedFormat.getChannels(); channel++) {
				try {
					int readCount = din.read(toBeConverted, 0, toBeConverted.length);

					ByteBuffer bBuffer = ByteBuffer.allocate(2);
					bBuffer.order(ByteOrder.LITTLE_ENDIAN);
					bBuffer.put(toBeConverted[0]);
					bBuffer.put(toBeConverted[1]);

					sampleAverage += bBuffer.getShort(0);

					if (readCount == -1) {
						break;
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

			sampleAverage /= decodedFormat.getChannels() * Short.MAX_VALUE + 1;
			samples[currentSample] = sampleAverage;
			sampleAverage = 0;
			samplesRead++;
		}
		return samplesRead;
	}

	@Override
	public AudioFormat getFormat() {
		return decodedFormat;
	}

	@Override
	public int getSampleCount() {
		return sampleCount;
	}

}
