package vermilion;

import java.util.ArrayList;

/**
 * A sampler machine being developed in conjunction with the sample bank and
 * proper track handling.
 */
public class MachineSampler extends MachineBase
{
    private ArrayList<UtilPlayingNote> playingNotes = new ArrayList<UtilPlayingNote>();
    private UtilTrackHandler trackHandler = new UtilTrackHandler();

    /**
     * The type for this machine is 'SOURCE'.
     */
    @Override
    public String getType()
    {
        return "SOURCE";
    }

    /**
     * The name for this machine is 'Sampler'.
     */
    @Override
    public String getName()
    {
        return "Sampler";
    }

    /**
     * This plugin does not require initialisation and does nothing.
     */
    @Override
    public void initialise()
    {
    }

    int counter = 0;

    /**
     * The mixing algorithm for this plugin...
     */
    @Override
    public void fillBuffer(int numSamples)
    {
        ArrayList<ArrayList<PlaybackEvent>> trackEvents = trackHandler.getTrackEvents();

        for (int x = 0; x < numSamples; x++)
        {
            output[0][x] = 0.0f;
            output[1][x] = 0.0f;
        }

        for (ArrayList<PlaybackEvent> tEvt : trackEvents)
        {
            //System.out.println("Event on track " + tEvt.get(0).trackNumber);
            
            UtilPlayingNoteSample newNote = new UtilPlayingNoteSample(tEvt.get(0).trackNumber);
            boolean noteLaunched = false;

            for (PlaybackEvent pEvt : tEvt)
            {
                if (pEvt.parameterID.equals("Note"))
                {
                    newNote.playbackPitch = ((ParameterNote) pEvt.commandVal).value;
                    noteLaunched = true;
                }
                else if (pEvt.parameterID.equals("Sample"))
                {
                    newNote.sampleIndex = ((ParameterSample) pEvt.commandVal).value;
                }
                else if (pEvt.parameterID.equals("Env"))
                {
                    newNote.envIndex = ((ParameterSample) pEvt.commandVal).value;
                }
                else if (pEvt.parameterID.equals("Cmd 1"))
                {
                    // TODO: Commands.
                }
                else if (pEvt.parameterID.equals("Cmd 2"))
                {
                    // TODO: Commands.
                }
            }

            if (noteLaunched)
            {
                //System.out.println("launching " + newNote);
                playingNotes.add(newNote);
            }
            else
            {
                // TODO: Handle commands on already playing notes.
            }
        }

        try
        {
            for (UtilPlayingNote note : playingNotes)
            {
                //System.out.println(note);
                note.mix(output, numSamples);
            }
        }
        catch (Exception ex)
        {
            System.out.println("Mixing error: ");
            ex.printStackTrace();
        }

        for (int y = 0; y < playingNotes.size(); y++)
        {
            if (playingNotes.get(y).isPlaying == false)
            {
                playingNotes.remove(y);
                y--;
            }
        }
    }

    /**
     * This machine sends events to the trackHandler which does the event
     * handling and creates playingNotes for us.
     */
    @Override
    public void parameterChange(PlaybackEvent param)
    {
        //System.out.println("Passing change " + param);
        trackHandler.handle(param);
    }

    /**
     * The setup for this machine creates the track parameters.
     */
    @Override
    public void setupMachine()
    {
        parameters = new ParameterBase[5];

        parameters[0] = new ParameterNote("Note", true);
        parameters[1] = new ParameterSample("Sample", true);
        parameters[2] = new ParameterSample("Env", true);
        parameters[3] = new ParameterCommand("Cmd 1", true);
        parameters[4] = new ParameterCommand("Cmd 2", true);
    }

    /**
     * This machine prints no values since none of the parameters are of a type
     * that is manipulated in a JParameterFrame.
     */
    @Override
    public String printParameter(ParameterBase p)
    {
        return "";
    }
}