package de.gurkenlabs.litiengine.sound;

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

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

import de.gurkenlabs.litiengine.util.io.FileUtilities;
import de.gurkenlabs.litiengine.util.io.StreamUtilities;

/**
 * This class implements all required functionality to load sounds from the file
 * system and provide a stream that can later on be used for the sound playback.
 */
public final class Sound {
  private static final Map<String, Sound> sounds = new ConcurrentHashMap<>();
  private static final Logger log = Logger.getLogger(Sound.class.getName());

  private AudioFormat format;

  private final String name;

  private AudioInputStream stream;

  private byte[] streamData;

  /**
   * Creates a new Sound instance by the specified file path. Loads the sound
   * data into a byte array and also retrieves information about the format of
   * the sound file.
   * 
   * Note that the constructor is private. In order to load files use the static
   * methods {@link #find(String)} or {@link #load(String)} methods depending on
   * whether you already loaded the sound or not.
   * 
   * @param is
   *          The input stream to load the sound from.
   */
  private Sound(InputStream is, String name) {
    this.name = name;

    try {
      AudioInputStream in = AudioSystem.getAudioInputStream(is);
      if (in != null) {
        final AudioFormat baseFormat = in.getFormat();
        final AudioFormat decodedFormat = this.getOutFormat(baseFormat);
        // Get AudioInputStream that will be decoded by underlying VorbisSPI
        in = AudioSystem.getAudioInputStream(decodedFormat, in);
        this.stream = in;
        this.streamData = StreamUtilities.getBytes(this.stream);
        this.format = this.stream.getFormat();
      }
    } catch (final UnsupportedAudioFileException | IOException e) {

      log.log(Level.SEVERE, e.getMessage(), e);
    }
  }

  /**
   * Finds and returns a sound previously loaded by calling the
   * {@link #load(String)} function.
   * 
   * @param name
   *          The name of the sound to find (no extension needed).
   * @return The sound that is identified by the specified name, if it was
   *         previously loaded or null.
   */
  public static Sound find(final String name) {
    if (name == null || name.isEmpty()) {
      return null;
    }
    
    final String fileName = FileUtilities.getFileName(name);
    
    if(!sounds.containsKey(fileName)) {      
      log.log(Level.SEVERE, "Could not find sound {0} because it was not loaded..", new Object[] { name });
      return null;
    }

    return sounds.get(fileName);
  }

  /**
   * Loads the sound from the specified path and makes it accessible via
   * {@link #find(String)} method.
   * 
   * @param path
   *          The path of the file to be loaded.(Can be relative or absolute)
   * @return The loaded Sound from the specified path.
   */
  public static Sound load(final String path) {
    String fileName = FileUtilities.getFileName(path);
    Sound sound = sounds.get(fileName);
    if (sound != null) {
      return sound;
    }

    final InputStream is = FileUtilities.getGameResource(path);
    if (is == null) {

      log.log(Level.SEVERE, "Could not load sound {0} because the game resource was not found.", new Object[] { path });
      return null;
    }

    sound = new Sound(is, fileName);
    sounds.put(fileName, sound);
    return sound;
  }

  public AudioFormat getFormat() {
    return this.format;
  }

  public String getName() {
    return this.name;
  }

  public byte[] getStreamData() {
    if (this.streamData == null) {
      return new byte[0];
    }

    return this.streamData.clone();
  }

  private AudioFormat getOutFormat(final AudioFormat inFormat) {
    final int ch = inFormat.getChannels();
    final float rate = inFormat.getSampleRate();
    return new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, rate, 16, ch, ch * 2, rate, false);
  }
}
@@ -1350,36 +1350,35 @@
 ng)%7D or %7B@link #
-load
+get
 (String)%7D method
@@ -2267,754 +2267,8 @@
 %0D%0A%0D%0A
-  /**%0D%0A   * Finds and returns a sound previously loaded by calling the%0D%0A   * %7B@link #load(String)%7D function.%0D%0A   * %0D%0A   * @param name%0D%0A   *          The name of the sound to find (no extension needed).%0D%0A   * @return The sound that is identified by the specified name, if it was%0D%0A   *         previously loaded or null.%0D%0A   */%0D%0A  public static Sound find(final String name) %7B%0D%0A    if (name == null %7C%7C name.isEmpty()) %7B%0D%0A      return null;%0D%0A    %7D%0D%0A    %0D%0A    final String fileName = FileUtilities.getFileName(name);%0D%0A    %0D%0A    if(!sounds.containsKey(fileName)) %7B      %0D%0A      log.log(Level.SEVERE, %22Could not find sound %7B0%7D because it was not loaded..%22, new Object%5B%5D %7B name %7D);%0D%0A      return null;%0D%0A    %7D%0D%0A%0D%0A    return sounds.get(fileName);%0D%0A  %7D%0D%0A%0D%0A
   /*
@@ -2569,20 +2569,19 @@
 c Sound 
-load
+get
 (final S

Remove the find method and rename the load method to get.