/***************************************************************************
 *   Copyright (C) 2009 by Paul Lutus                                      *
 *   lutusp@arachnoid.com                                                  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
package fftexplorer;

import java.io.*;
import javax.swing.*;
import java.util.*;

import javax.sound.sampled.*;

/**
 *
 * @author lutusp
 */
public class MP3Stream {

    boolean playing = false;
    boolean suspend = false;
    FFTExplorer parent;
    Thread streamThread = null;
    int sampleRate;

    public MP3Stream(FFTExplorer p) {
        parent = p;
    }

    public boolean playing() {
        return playing;
    }

    public int sampleRate() {
        return sampleRate;
    }

    public void suspend(boolean susp) {
        suspend = susp;
    }

    public void stopStream() {
        playing = false;
        if (streamThread != null) {
            try {
                streamThread.join();
            } catch (Exception e) {
            }
            streamThread = null;
        }
        parent.streamMP3ButtonControl(false);
    }

    String chooseSoundFile(String currentSelection) {
        String result = null;
        JFileChooser chooser = new JFileChooser();
        // avoid the GTK L&F terrible appearance
        // for this one component
        boolean changed = parent.changeLookAndFeel(chooser);

        AudioFileFilter filter = new AudioFileFilter();

        chooser.setFileFilter(filter);

        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        chooser.setDialogTitle(parent.appName + ": Choose Sound File");
        chooser.setApproveButtonText("Accept");
        chooser.setCurrentDirectory(new File(parent.sv_soundSourceDirectory));
        if (currentSelection != null) {
            chooser.setSelectedFile(new File(currentSelection));
        }
        int returnVal = chooser.showOpenDialog(parent);
        if (changed) {
            parent.restoreSystemLookAndFeel();
        }
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            try {
                parent.sv_soundSourceDirectory = chooser.getSelectedFile().getCanonicalPath();
                result = chooser.getSelectedFile().toString();
            //System.out.println(parent.sv_soundSourceDirectory);
            //readGraphicDirectory(parent.sv_editSearchDirectory);
            } catch (Exception e) {
                System.out.println(e);
            }
        }
        return result;
    }

    public void streamMP3(final int arraySize) {
        stopStream();
        playing = true;
        final String filePath = chooseSoundFile(parent.sv_soundSourceDirectory);
        if (filePath != null) {
            streamThread = new Thread() {

                @Override
                public void run() {
                    streamMP3Thread(filePath, arraySize);
                }
            };
            streamThread.start();
        }
    }

    public void streamMP3Thread(String filePath, int arraySize) {
        try {
            suspend = false;
            parent.signalProcessor.initialize(false);
            Vector<Float> vf = new Vector<Float>();
            AudioInputStream in = AudioSystem.getAudioInputStream(new File(filePath));
            AudioFormat baseFormat = in.getFormat();
            sampleRate = (int) baseFormat.getSampleRate();
            parent.setSampleRate();
            AudioFormat decodedFormat = new AudioFormat(
                    AudioFormat.Encoding.PCM_SIGNED, // Encoding to use
                    baseFormat.getSampleRate(), // sample rate (same as base format)
                    16, // sample size in bits
                    baseFormat.getChannels(), // # of Channels
                    baseFormat.getChannels() * 2, // Frame Size
                    //1,2, // mono mode
                    baseFormat.getSampleRate(), // Frame Rate
                    false // Big Endian
                    );
            //parent.p("decoded format: " + decodedFormat);
            AudioInputStream stream = AudioSystem.getAudioInputStream(decodedFormat, in);

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

            SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
            line.open(decodedFormat);
            if (line != null) {
                byte[] data = new byte[arraySize];
                // Start
                line.start(); // Start the line.

                int nBytesRead = 0;
                float a, b;
                parent.mp3StreamProgressBar.setString("Relative Length");
                parent.mp3StreamProgressBar.setStringPainted(true);
                while (playing && nBytesRead != -1) {
                    if (suspend) {
                        Thread.sleep(250);
                    } else {
                        nBytesRead = stream.read(data, 0, data.length);
                        if (nBytesRead != -1) {
                            //parent.p("data length: " + nBytesRead);
                            line.write(data, 0, nBytesRead);
                            int msp = (int) line.getMicrosecondPosition() / 1000000; // seconds
                            msp %= 100;
                            parent.mp3StreamProgressBar.setValue(msp);
                            // get mono signed values for graph
                            for (int i = 0; i < nBytesRead; i += 4) {
                                a = (data[i + 1] << 8) | data[i] & 0xff;
                                b = (data[i + 3] << 8) | data[i + 2] & 0xff;
                                vf.add((a + b) / 2);
                            }
                            parent.signalProcessor.readAudio(vf);
                        }
                    }
                }
                // Stop
                line.drain();
                line.stop();
                line.close();
                line = null;
                stream.close();
                parent.streamMP3ButtonControl(false);
            } else {
                throw new Exception("streamMP3Thread: line.open() failed");
            }
        } catch (Exception e) {
            System.out.println("Problem playing file " + filePath + ": " + e);
            e.printStackTrace();
        }
    }
}
