package ei.engine.sound;

import java.io.IOException;
import java.io.InputStream;
import java.nio.IntBuffer;
import java.util.HashMap;

import org.lwjgl.BufferUtils;
import org.lwjgl.Sys;
import org.lwjgl.openal.AL10;
import org.lwjgl.util.WaveData;

import ei.engine.sound.decoders.OggData;
import ei.engine.sound.decoders.OggDecoder;
import ei.engine.util.MultiPrintStream;

/**
 * Responsible for holding and playing the sounds used in the game.
 * 
 * @author Kevin Glass
 * @author Ziver Koc
 */
public class SoundLoader {
	/** The single instance of this class */
	private static SoundLoader instance = new SoundLoader();
	
	/** The map of references to IDs of previously loaded sounds */
	private HashMap<String, Integer> loaded = new HashMap<String, Integer>();

	
	/**
	 * Create a new sound store
	 */
	private SoundLoader() {

	}

	/**
	 * Get the Sound based on a specified file path in the classpath
	 * 
	 * @param ref The reference to the file in the classpath
	 * @return An integer value that represents the buffer -1 if sound is disabled
	 * @throws IOException Indicates a failure to load the sound file
	 */
	public int loadSound(String ref){
		if (!SoundManager.getInstnace().isEnabled()) {
			return -1;
		}
		int buffer = -1;
		
		if (loaded.get(ref) != null) {
			buffer = ((Integer) loaded.get(ref)).intValue();
		} 
		else {
			MultiPrintStream.out.println("Loading sound: "+ref);
			try {
				IntBuffer buf = BufferUtils.createIntBuffer(1);				
				InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(ref);
				String extension = getFileExtension(ref);
				AL10.alGenBuffers(buf);
				
				if(extension.equals("ogg")){
					//loading ogg format
					OggDecoder decoder = new OggDecoder();
					OggData ogg = decoder.getData(in);
					AL10.alBufferData(buf.get(0), ogg.channels > 1 ? AL10.AL_FORMAT_STEREO16 : AL10.AL_FORMAT_MONO16, ogg.data, ogg.rate);
				}
				else if(extension.equals("wav")){
					//loading wav format
				    WaveData wav = WaveData.create(in);
				    AL10.alBufferData(buf.get(0), wav.format, wav.data, wav.samplerate);
				    wav.dispose();
				}
				else{
					MultiPrintStream.out.println("Unknown file format: "+ref);
					return -1;
				}
				
				loaded.put(ref,new Integer(buf.get(0)));
				                     
				buffer = buf.get(0);
			} catch (Exception e) {
				e.printStackTrace();
				Sys.alert("ERROR", "Failed to load: "+ref+" - "+e.getMessage());
				MultiPrintStream.out.println("Failed to load: "+ref+" - "+e.getMessage());
				SoundManager.getInstnace().setEnabled(false);
				return -1;
			}
		}
		
		return buffer;
	}
	
	/**
	 * Returns the file extension
	 * @param file The path to the file
	 * @return The file extension
	 */
	private String getFileExtension(String file){
		int dot = file.lastIndexOf ( '.' );
	
		if ( dot >= 0 ){
			return file.substring(dot + 1, file.length());
		}
		else{
			return "";
		}
	}

	/**
	 * Get the single instance of this class
	 * 
	 * @return The single instnace of this class
	 */
	public static SoundLoader getInstnace() {
		if(instance == null){
			instance = new SoundLoader();
		}
		return instance;
	}
}
