package framework;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.DataLine;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
import framework.Sound;
import framework.generators.Generator;

/**
 * Manage a list of Sound objects.
 *
 * This class provides methods to play, pause and mix different sounds.
 */
public class Player {
    public Player() {
        try {
            // 44,100 samples per second, 16-bit audio, mono, signed PCM, little Endian
            AudioFormat format = new AudioFormat(
                (float) Generator.SAMPLE_RATE, BITS_PER_SAMPLE, 1, true, false);

            DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);

            line = (SourceDataLine) AudioSystem.getLine(info);
            line.open(format, SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE);

            // The internal buffer is a fraction of the actual buffer size
            // It gets divided because we can't expect the buffered data to line up
            // exactly with when the sound card decides to push out its samples.
            buffer = new byte[SAMPLE_BUFFER_SIZE * BYTES_PER_SAMPLE/3];
        } catch (Exception e) {
            System.out.println(e.getMessage());
            System.exit(1);
        }

        playlist = new HashMap<Sound, Boolean>();
    }

    /**
     * Add the specified Sound to the playlist.
     * @param s the sound to be added
     */
    public void addSound(Sound s) {
        playlist.put(s, true);
    }

    /**
     * Remove the specified Sound from the playlist.
     * @param s the Sound to be removed
     */
    public void removeSound(Sound s) {
        playlist.remove(s);
    }

    /**
     * Toggle a Sound inside the playlist.
     *
     * If its value is true, it is added to the mix.
     * If its value is false, it is muted.
     * @param s the Sound to be toggled
     */
    public void toggleSound(Sound s) {
        if(playlist.get(s) != null)
            playlist.put(s, !playlist.get(s));
    }

    /**
     * Play all the Sound objects which are not muted.
     */
    public void play() {
        ArrayList<Sound> selection = new ArrayList<Sound>();

        for(Map.Entry<Sound, Boolean> entry : playlist.entrySet()) {
            if(entry.getValue()) {

            }
        }

        line.start();

        double[] data = entry.getKey().getData();
                for(int i = 0; i < data.length; i++) {
                    // Clip
                    if (data[i] < -1.0) data[i] = -1.0;
                    if (data[i] > +1.0) data[i] = +1.0;

                    // Convert to bytes
                    short s = (short) (MAX_16_BIT * data[i]);
                    buffer[bufferSize++] = (byte) s;
                    buffer[bufferSize++] = (byte) (s >> 8);   // little Endian

                    // Send to sound card if buffer is full
                    if (bufferSize >= buffer.length) {
                        line.write(buffer, 0, buffer.length);
                        bufferSize = 0;
                    }
                }

        line.drain();
        line.stop();
    }

    private SourceDataLine              line;
    private HashMap<Sound, Boolean>     playlist;
    private byte[]                      buffer; // Internal buffer
    private int                         bufferSize = 0; // Current number of samples in buffer

    // Constants
    private final int       BYTES_PER_SAMPLE    = 2;
    private final int       BITS_PER_SAMPLE     = 16;
    private final double    MAX_16_BIT          = Short.MAX_VALUE;
    private final int       SAMPLE_BUFFER_SIZE  = 4096;
}
@@ -2266,136 +2266,8 @@
 );%0A%0A
-        for(Map.Entry%3CSound, Boolean%3E entry : playlist.entrySet()) %7B%0A            if(entry.getValue()) %7B%0A%0A            %7D%0A        %7D
 %0A%0A  
@@ -3072,24 +3072,437 @@
 p();%0A    %7D%0A%0A
+    /**%0A     * Get all the Sound objects that are not muted.%0A     * @return The list of Sound objects%0A     */%0A    public ArrayList%3CSound%3E getPlayableSounds() %7B%0A        ArrayList%3CSound%3E selection = new ArrayList%3CSound%3E();%0A        for(Map.Entry%3CSound, Boolean%3E entry : playlist.entrySet()) %7B%0A            if(entry.getValue())%0A                selection.add(entry.getKey());%0A        %7D%0A        return selection;%0A    %7D%0A%0A
     private 

Add getPlayableSounds method to Player.