package vermilion;

import java.io.File;
import java.util.ArrayList;
import javax.sound.sampled.*;

public class SampleSampledAudio extends SampleObject
{
    public int numChannels = 0;
    public int length = 0;
    public int sampleRate = 0;
    
    public float[][] sampleData;

    @Override
    public String getType()
    {
        return "SAMPLE";
    }

    @Override
    public int getVersion()
    {
        return 1;
    }

    @Override
    public String saveImpl()
    {
        ArrayList<String> list = new ArrayList<String>();
        list.add(String.valueOf(numChannels));
        list.add(String.valueOf(length));
        list.add(String.valueOf(sampleRate));

        StringBuilder sb = new StringBuilder();

        for (int x = 0; x < numChannels; x++)
        {
            for (int y = 0; y < length; y++)
            {
                int bits = Float.floatToIntBits(sampleData[x][y]);
                sb.append((char) (bits & 0xFFFF));
                sb.append((char) ((bits >>> 16) & 0xFFFF));
            }

            list.add(sb.toString());
            sb.setLength(0);
        }

        return listToString(list);
    }

    @Override
    public UsefulFileObject loadImpl(String str, int version)
    {
        //System.out.println("Loading sample");

        try
        {
            SampleSampledAudio newObj = new SampleSampledAudio();

            ArrayList<String> list = stringToList(str);

            newObj.numChannels = Integer.parseInt(list.get(0));
            newObj.length = Integer.parseInt(list.get(1));
            newObj.sampleRate = Integer.parseInt(list.get(2));

            newObj.sampleData = new float[newObj.numChannels][newObj.length];

            //System.out.println(numChannels + " X " + length);

            for (int x = 0; x < newObj.numChannels; x++)
            {
                String chStr = list.get(3+x);
                for (int y = 0; y < newObj.length; y++)
                {
                    int bits = 0;
                    bits = bits | chStr.charAt(y*2+1);
                    bits = bits << 16;
                    bits = bits | chStr.charAt(y*2);

                    newObj.sampleData[x][y] = Float.intBitsToFloat(bits);
                }
            }

            return newObj;
        }
        catch (Exception ex)
        {
            System.out.println("error loading sample: " + ex.toString());
        }

        return null;
    }

    @Override
    public boolean loadFile(String fileName)
    {
        try
        {

            File fileIn = new File(fileName);


            // TODO: Put all this in a method and have other ways to try later
            // e.g. for MP3s.
            //int totalFramesRead = 0;
            try
            {
                AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(fileIn);
                ArrayList<Float> loadedData = new ArrayList<Float>();

                // @todo: working here on loading audio.
                AudioFormat fmt = audioInputStream.getFormat();
                AudioStreamHandler ash = new AudioStreamHandler(fmt);

                System.out.println("Trying to load Java supported format " + fmt);

                // Set an arbitrary buffer size of 64K.
                int numBytes = 1024 * 64;
                byte[] audioBytes = new byte[numBytes];
                try
                {
                    int numBytesRead = 0;

                    // Try to read numBytes bytes from the file.
                    while ((numBytesRead = audioInputStream.read(audioBytes)) != -1)
                    {
                        loadedData.addAll(ash.processData(audioBytes, numBytesRead));
                    }

                    // Use AudioFormat to decode data into channel arrays now.
                    numChannels = fmt.getChannels();
                    length = loadedData.size() / numChannels;
                    sampleData = new float[numChannels][length];
                    sampleRate = (int) fmt.getSampleRate();

                    for (int y = 0; y < length; y++)
                    {
                        for (int x = 0; x < numChannels; x++)
                        {
                            sampleData[x][y] = loadedData.get(y*numChannels+x);
                        }
                    }

                    return true;
                }
                catch (Exception ex)
                {
                    // Handle stream read error...
                    System.out.println(ex.toString());
                    return false;
                }
            }
            catch (Exception ex)
            {
                // Handle audio format error...
                System.out.println(ex.toString());
                return false;
            }
        }
        catch (Exception ex)
        {
            // Handle file open error...
            System.out.println(ex.toString());
            return false;
        }

        //return false;
    }

    @Override
    public String toString()
    {
        return "Sampled Audio: " + length*1000/sampleRate + " ms, " + numChannels + " channels";
    }
}
