package com.uoc.educationalVG.framework.impl;

import java.io.IOException;

import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;

import com.uoc.educationalVG.framework.Music;

public class AndroidMusic implements Music, OnCompletionListener {
	MediaPlayer mediaPlayer;

	// we can only call MediaPlayer.start()/stop()/pause() when the MediaPlayer
	// is prepared.
	boolean isPrepared = false;

	/**
	 * In the constructor, we create and prepare the MediaPlayer from the
	 * AssetFileDescriptor that is passed in, and we set the isPrepared flag, as
	 * well as register the AndroidMusic instance as an OnCompletionListener
	 * with the MediaPlayer. If anything goes wrong, we throw an unchecked
	 * RuntimeException once again.
	 * 
	 * @param assetDescriptor
	 */
	public AndroidMusic(AssetFileDescriptor assetDescriptor) {
		mediaPlayer = new MediaPlayer();
		try {
			mediaPlayer.setDataSource(assetDescriptor.getFileDescriptor(),
					assetDescriptor.getStartOffset(),
					assetDescriptor.getLength());
			mediaPlayer.prepare();
			isPrepared = true;
			mediaPlayer.setOnCompletionListener(this);
		} catch (Exception e) {
			throw new RuntimeException("Couldn't load music");
		}
	}

	/**
	 * Checks if the MediaPlayer is still playing and, if so, stops it.
	 * Otherwise, the call to MediaPlayer.release() will throw a runtime
	 * exception.
	 */
	@Override
	public void dispose() {
		if (mediaPlayer.isPlaying())
			mediaPlayer.stop();
		mediaPlayer.release();
	}

	@Override
	public boolean isLooping() {
		return mediaPlayer.isLooping();
	}

	@Override
	public boolean isPlaying() {
		return mediaPlayer.isPlaying();
	}

	@Override
	public boolean isStopped() {
		return !isPrepared;
	}

	/**
	 * Checks whether the MediaPlayer instance is playing and calls its pause()
	 * method if it is.
	 */
	@Override
	public void pause() {
		if (mediaPlayer.isPlaying())
			mediaPlayer.pause();
	}

	/**
	 * If we are already playing, we simply return from the function. Next we
	 * have a mighty try...catch block within which we check to see if the
	 * MediaPlayer is already prepared based on our flag; we prepare it if
	 * needed. If all goes well, we call the MediaPlayer.start() method, which
	 * will start the playback. This is conducted in a synchronized block, since
	 * we are using the isPrepared flag, which might get set on a separate
	 * thread because we are implementing the OnCompletionListener interface. In
	 * case something goes wrong, we throw an unchecked RuntimeException.
	 */
	@Override
	public void play() {
		if (mediaPlayer.isPlaying())
			return;

		try {
			synchronized (this) {
				if (!isPrepared)
					mediaPlayer.prepare();
				mediaPlayer.start();
			}
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void setLooping(boolean isLooping) {
		mediaPlayer.setLooping(isLooping);
	}

	@Override
	public void setVolume(float volume) {
		mediaPlayer.setVolume(volume, volume);
	}

	/**
	 * Stops the MediaPlayer and sets the isPrepared flag in a synchronized
	 * block.
	 */
	@Override
	public void stop() {
		mediaPlayer.stop();
		synchronized (this) {
			isPrepared = false;
		}
	}

	/**
	 * Sets the isPrepared flag in a synchronized block so that the other
	 * methods don’t start throwing exceptions out of the blue. 
	 */
	@Override
	public void onCompletion(MediaPlayer player) {
		synchronized (this) {
			isPrepared = false;
		}
	}
}
