/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package moppydesk.ui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.midi.Transmitter;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JSlider;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.TableColumnModel;
import moppydesk.Constants;
import moppydesk.MoppyStatusConsumer;
import moppydesk.MoppyUI;
import moppydesk.inputs.MoppySequencer;
import moppydesk.playlist.MoppyPlaylist;

/**
 *
 * @author Sam/AJ (MrSolidSnake745)
 * 
 */

public class PlaylistControls extends InputPanel implements MoppyStatusConsumer {

    MoppySequencer seq;
    MoppyControlWindow controlWindow;
    MoppyUI app;
    final JFileChooser sequenceChooser = new JFileChooser();    
    final FileNameExtensionFilter MIDIFilter = new FileNameExtensionFilter("MIDI Files (*.mid, *.midi)", "mid", "midi");
    final FileNameExtensionFilter MPLFilter = new FileNameExtensionFilter("Moppy Playlist Files", "mpl");
    Timer progressTimer;
    private boolean isConnected = false;
    private boolean fileLoaded = false;
    private boolean interruptNextSong = false;
    MoppyPlaylist playlist = new MoppyPlaylist();

    /**
     * Creates new form PlaylistControls
     */
    public PlaylistControls(MoppyUI app, MoppyControlWindow mcw, MoppySequencer newSequencer) {
        this.seq = newSequencer;
        this.app = app;
        this.controlWindow = mcw;

        initComponents();

        progressTimer = new Timer(1000, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                updateProgressDisplay();
            }
        });
        
        setupPlaylistTable();
        sequenceChooser.addChoosableFileFilter(MIDIFilter);
        sequenceChooser.addChoosableFileFilter(MPLFilter);
    }

    
    @Override
    public void savePreferences() {
        //Nothing to do here! All prefs are saved upon UI actions currently
    }
    
    @Override
    public void loadPreferences() {
        loadLastListCheckbox.setSelected(app.prefs.getBoolean(Constants.PREF_LOAD_MPL_ON_START, false));
        String previouslyLoaded = app.prefs.get(Constants.PREF_LOADED_MPL, null);
        if (previouslyLoaded != null && !previouslyLoaded.isEmpty() && loadLastListCheckbox.isSelected()) { 
            //Try to load the last MPL, if it fails, clear out the preference
            if (!loadPlaylist(new File(previouslyLoaded))) { app.prefs.put(Constants.PREF_LOADED_MPL, ""); }                           
        }
    }    
    
    private void updateProgressDisplay() {
        long currentSeconds = seq.getSecondsPosition();
        sequenceProgressSlider.setValue((int) (currentSeconds));
        String currentPosition = String.format("%d:%02d",
                TimeUnit.SECONDS.toMinutes(currentSeconds),
                currentSeconds % 60);
        String totalPosition = String.format("%d:%02d",
                TimeUnit.SECONDS.toMinutes(seq.getSecondsLength()),
                seq.getSecondsLength() % 60);
        currentPositionLabel.setText(currentPosition);
        totalPositionLabel.setText(totalPosition);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        sequenceNameLabel = new javax.swing.JLabel();
        bpmLabel = new javax.swing.JLabel();
        clearButton = new javax.swing.JButton();
        loadButton = new javax.swing.JButton();
        sequenceProgressSlider = new javax.swing.JSlider();
        currentPositionLabel = new javax.swing.JLabel();
        totalPositionLabel = new javax.swing.JLabel();
        resetListButton = new javax.swing.JButton();
        resetDrivesCheckbox = new javax.swing.JCheckBox();
        loadListButton = new javax.swing.JButton();
        saveListButton = new javax.swing.JButton();
        playlistScrollPane = new javax.swing.JScrollPane();
        playlistTable = new javax.swing.JTable();
        jPanel1 = new javax.swing.JPanel();
        previousButton = new javax.swing.JButton();
        startButton = new javax.swing.JButton();
        stopButton = new javax.swing.JButton();
        nextButton = new javax.swing.JButton();
        loadDirectoryButton = new javax.swing.JButton();
        randomizeButton = new javax.swing.JButton();
        loadLastListCheckbox = new javax.swing.JCheckBox();

        setMaximumSize(new java.awt.Dimension(529, 240));
        setMinimumSize(new java.awt.Dimension(0, 0));
        setName(""); // NOI18N
        setOpaque(false);
        setPreferredSize(new java.awt.Dimension(524, 240));
        setRequestFocusEnabled(false);

        sequenceNameLabel.setText("<None loaded>");

        bpmLabel.setText("? bpm");
        bpmLabel.setAlignmentX(1.0F);

        clearButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
        clearButton.setText("Clear List");
        clearButton.setToolTipText("");
        clearButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        clearButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clearButtonstopResetClicked(evt);
            }
        });

        loadButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
        loadButton.setLabel("Load MIDI");
        loadButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        loadButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadButtonloadSequence(evt);
            }
        });

        sequenceProgressSlider.setToolTipText("");
        sequenceProgressSlider.setValue(0);
        sequenceProgressSlider.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseDragged(java.awt.event.MouseEvent evt) {
                sequenceProgressDragged(evt);
            }
        });
        sequenceProgressSlider.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                sequenceProgressDragged(evt);
            }
        });

        currentPositionLabel.setText("00:00");

        totalPositionLabel.setText("00:00");

        resetListButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
        resetListButton.setText("Reset List");
        resetListButton.setToolTipText("");
        resetListButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        resetListButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                resetListButtonstopResetClicked(evt);
            }
        });

        resetDrivesCheckbox.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
        resetDrivesCheckbox.setText("Reset drives");
        resetDrivesCheckbox.setToolTipText("If selected, will reset the drives to the intial position between songs");
        resetDrivesCheckbox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                resetDrivesCheckboxActionPerformed(evt);
            }
        });

        loadListButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
        loadListButton.setText("Load List");
        loadListButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        loadListButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadListButtonActionPerformed(evt);
            }
        });

        saveListButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
        saveListButton.setText("Save List");
        saveListButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        saveListButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveListButtonActionPerformed(evt);
            }
        });

        playlistTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {

            },
            new String [] {

            }
        ));
        playlistTable.getTableHeader().setReorderingAllowed(false);
        playlistScrollPane.setViewportView(playlistTable);

        previousButton.setText("◄◄");
        previousButton.setToolTipText("Previous");
        previousButton.setEnabled(false);
        previousButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        previousButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                previousButtonActionPerformed(evt);
            }
        });
        jPanel1.add(previousButton);

        startButton.setText(" ► ");
        startButton.setToolTipText("Start/Pause");
        startButton.setEnabled(false);
        startButton.setMargin(new java.awt.Insets(2, 3, 2, 3));
        startButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startButtonActionPerformed(evt);
            }
        });
        jPanel1.add(startButton);

        stopButton.setText("■");
        stopButton.setToolTipText("Stop/Reset - Click while stopped to reset drives");
        stopButton.setMargin(new java.awt.Insets(2, 7, 2, 7));
        stopButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopButtonActionPerformed(evt);
            }
        });
        jPanel1.add(stopButton);

        nextButton.setText("►►");
        nextButton.setToolTipText("Next");
        nextButton.setEnabled(false);
        nextButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        nextButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                nextButtonActionPerformed(evt);
            }
        });
        jPanel1.add(nextButton);

        loadDirectoryButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
        loadDirectoryButton.setText("Load Directory");
        loadDirectoryButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        loadDirectoryButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadDirectoryButtonloadSequence(evt);
            }
        });

        randomizeButton.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
        randomizeButton.setText("Randomize");
        randomizeButton.setMargin(new java.awt.Insets(2, 2, 2, 2));
        randomizeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                randomizeButtonActionPerformed(evt);
            }
        });

        loadLastListCheckbox.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
        loadLastListCheckbox.setText("Load last MPL on startup");
        loadLastListCheckbox.setToolTipText("If selected, will load the last successfully loaded MPL file");
        loadLastListCheckbox.setActionCommand("Load last MPL on startup");
        loadLastListCheckbox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadLastListCheckboxActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(2, 2, 2)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(currentPositionLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(sequenceProgressSlider, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(totalPositionLabel))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(loadListButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(saveListButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(randomizeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(loadLastListCheckbox)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(sequenceNameLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(bpmLabel))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(playlistScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 425, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addGap(2, 2, 2)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(loadButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                    .addComponent(resetDrivesCheckbox, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 87, Short.MAX_VALUE)
                                    .addComponent(loadDirectoryButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                            .addComponent(clearButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(resetListButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
                .addGap(2, 2, 2))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(2, 2, 2)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(loadButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(loadDirectoryButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(resetListButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(clearButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(resetDrivesCheckbox))
                    .addComponent(playlistScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(loadListButton)
                        .addComponent(saveListButton)
                        .addComponent(randomizeButton)
                        .addComponent(loadLastListCheckbox))
                    .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 20, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(sequenceNameLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(sequenceProgressSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(bpmLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(currentPositionLabel)
                            .addComponent(totalPositionLabel))))
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    private void playSequencer() {
        if(!(fileLoaded) && !(playlist.isFinished())) {            
            loadSequenceFile(playlist.getNextSong());            
        }        
        seq.startSequencer();        
        controlWindow.setStatus("Playing!");
        startButton.setText("▐ ▌");
    }

    private void pauseSequencer() {
        seq.stopSequencer();        
        startButton.setText(" ► ");
        controlWindow.setStatus("...Paused");
    }    
    
    private void stopResetSequencer() {
        if (seq.isRunning()) {
            controlWindow.setStatus("Stopping...");
            seq.stopSequencer();            
            seq.resetSequencer();
            startButton.setText(" ► ");
            controlWindow.setStatus("Stopped.");
        } else {
            app.rm.reset();
            controlWindow.setStatus("Reset.");
        }
    }        
    
    private void clearButtonstopResetClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonstopResetClicked
        clearPlaylist();
    }//GEN-LAST:event_clearButtonstopResetClicked

    private void loadButtonloadSequence(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadButtonloadSequence
        String previouslyLoaded = app.prefs.get(Constants.PREF_LOADED_LIST, null);
        if (previouslyLoaded != null) {
            sequenceChooser.setCurrentDirectory(new File(previouslyLoaded));
        }   
        sequenceChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        sequenceChooser.setFileFilter(MIDIFilter);
        int returnVal = sequenceChooser.showOpenDialog(this);

        if (returnVal == JFileChooser.APPROVE_OPTION) {
            app.prefs.put(Constants.PREF_LOADED_LIST, sequenceChooser.getSelectedFile().getPath());
            playlist.addSong(sequenceChooser.getSelectedFile());            
            
            if (isConnected && !(playlist.isFinished())) {
                startButton.setEnabled(true);
            }
        } else {
            //Cancelled
        }
    }//GEN-LAST:event_loadButtonloadSequence

    private void sequenceProgressDragged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_sequenceProgressDragged
        int seconds = ((JSlider) evt.getSource()).getValue();
        seq.setSecondsPosition(seconds);
        currentPositionLabel.setText(String.format("%d:%02d",
                TimeUnit.SECONDS.toMinutes(seconds),
                seconds % 60));
    }//GEN-LAST:event_sequenceProgressDragged

    private void resetListButtonstopResetClicked(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetListButtonstopResetClicked
        resetPlaylist();
    }//GEN-LAST:event_resetListButtonstopResetClicked

    private void loadListButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadListButtonActionPerformed
        loadPlaylist(getPlaylistFile(true));
    }//GEN-LAST:event_loadListButtonActionPerformed

    private void saveListButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveListButtonActionPerformed
        savePlaylist(getPlaylistFile(false));
    }//GEN-LAST:event_saveListButtonActionPerformed

    private void resetDrivesCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetDrivesCheckboxActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_resetDrivesCheckboxActionPerformed

    private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startButtonActionPerformed
        if (startButton.getText().equals(" ► ")) {
            interruptNextSong = false;
            playSequencer();
        } else {
            pauseSequencer();
        }
    }//GEN-LAST:event_startButtonActionPerformed

    private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopButtonActionPerformed
        stopResetSequencer();
    }//GEN-LAST:event_stopButtonActionPerformed

    private void nextButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextButtonActionPerformed
        if(!playlist.isLastSong()) {
            try {
                loadSequenceFile(playlist.getNextSong());                              
                if(isConnected) {Thread.sleep(1000); playSequencer();}
            } catch (InterruptedException ex) {
                Logger.getLogger(PlaylistControls.class.getName()).log(Level.SEVERE, null, ex);
                controlWindow.setStatus("Error playing next song!");
                JOptionPane.showMessageDialog(this.getRootPane(), ex);
            }
        }        
    }//GEN-LAST:event_nextButtonActionPerformed

    private void previousButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_previousButtonActionPerformed
        if(!playlist.isFirstSong()) {
            try {
                loadSequenceFile(playlist.getPreviousSong());                        
                if(isConnected) {Thread.sleep(1000); playSequencer();}
            } catch (InterruptedException ex) {
                Logger.getLogger(PlaylistControls.class.getName()).log(Level.SEVERE, null, ex);
                controlWindow.setStatus("Error playing previous song!");
                JOptionPane.showMessageDialog(this.getRootPane(), ex);
            }
        }
    }//GEN-LAST:event_previousButtonActionPerformed

    private void loadDirectoryButtonloadSequence(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadDirectoryButtonloadSequence
        String previouslyLoaded = app.prefs.get(Constants.PREF_LOADED_LIST, null);
        if (previouslyLoaded != null) {
            sequenceChooser.setCurrentDirectory(new File(previouslyLoaded));
        }
        
        sequenceChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        sequenceChooser.setFileFilter(sequenceChooser.getAcceptAllFileFilter());
        int returnVal = sequenceChooser.showOpenDialog(this);

        if (returnVal == JFileChooser.APPROVE_OPTION) {
            app.prefs.put(Constants.PREF_LOADED_LIST, sequenceChooser.getSelectedFile().getPath());
            for (File file : sequenceChooser.getSelectedFile().listFiles()) {
                String extension = file.getName().substring(file.getName().lastIndexOf(".") + 1, file.getName().length());
                if("mid".equals(extension) || "midi".equals(extension)) {playlist.addSong(file);}
            }            
                        
            sequenceChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            if (isConnected && !(playlist.isFinished())) {startButton.setEnabled(true);}
        } else {
            //Cancelled
        }
        sequenceChooser.setAcceptAllFileFilterUsed(true);
    }//GEN-LAST:event_loadDirectoryButtonloadSequence

    private void randomizeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_randomizeButtonActionPerformed
        playlist.randomize();
    }//GEN-LAST:event_randomizeButtonActionPerformed

    private void loadLastListCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadLastListCheckboxActionPerformed
        app.prefs.putBoolean(Constants.PREF_LOAD_MPL_ON_START, loadLastListCheckbox.isSelected());
    }//GEN-LAST:event_loadLastListCheckboxActionPerformed
        
    @Override
    public void tempoChanged(int newTempo) {
        bpmLabel.setText(newTempo + " bpm");
    }
    
    @Override
    public void sequenceEnded() {                
        try {
            playlist.currentSongFinished();
            if (!(playlist.isFinished())) {
                loadSequenceFile(playlist.getNextSong());                
                if(resetDrivesCheckbox.isSelected()) {Thread.sleep(500); app.rm.reset(); Thread.sleep(500);}
                Thread.sleep(3000);
                if(interruptNextSong) {interruptNextSong = false;}
                else {playSequencer();}
            }
            else {
                playlistEnded();                
            }
        }
        catch (InterruptedException ex) {
            Logger.getLogger(MoppyControlWindow.class.getName()).log(Level.SEVERE, null, ex);
            controlWindow.setStatus("Error playing next song!");
            JOptionPane.showMessageDialog(this.getRootPane(), ex);
        }        
    }

    private void loadSequenceFile(File sequenceFile) {
        try {
            controlWindow.setStatus("Loading file...");
            seq.loadFile(sequenceFile.getPath());
            sequenceNameLabel.setText(playlist.getCurrentSongName());
            sequenceProgressSlider.setMaximum((int) (seq.getSecondsLength()));                        
            controlWindow.setStatus("Loaded " + sequenceFile.getName());
            updateProgressDisplay();
            fileLoaded = true;
        } catch (Exception ex) {
            Logger.getLogger(MoppyControlWindow.class.getName()).log(Level.SEVERE, null, ex);
            controlWindow.setStatus("File loading error!");
            JOptionPane.showMessageDialog(this.getRootPane(), ex);
            fileLoaded = false;
        }
        enableNextPrev();
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel bpmLabel;
    private javax.swing.JButton clearButton;
    private javax.swing.JLabel currentPositionLabel;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JButton loadButton;
    private javax.swing.JButton loadDirectoryButton;
    private javax.swing.JCheckBox loadLastListCheckbox;
    private javax.swing.JButton loadListButton;
    private javax.swing.JButton nextButton;
    private javax.swing.JScrollPane playlistScrollPane;
    private javax.swing.JTable playlistTable;
    private javax.swing.JButton previousButton;
    private javax.swing.JButton randomizeButton;
    private javax.swing.JCheckBox resetDrivesCheckbox;
    private javax.swing.JButton resetListButton;
    private javax.swing.JButton saveListButton;
    private javax.swing.JLabel sequenceNameLabel;
    private javax.swing.JSlider sequenceProgressSlider;
    private javax.swing.JButton startButton;
    private javax.swing.JButton stopButton;
    private javax.swing.JLabel totalPositionLabel;
    // End of variables declaration//GEN-END:variables

    @Override
    public Transmitter getTransmitter() {
        return seq;
    }

    @Override
    public void connected() {
        progressTimer.start();
        isConnected = true;
        if (!(playlist.isFinished())) {startButton.setEnabled(true);}
    }

    @Override
    public void disconnected() {
        startButton.setEnabled(false);
        pauseSequencer();
        isConnected = false;
        progressTimer.stop();
        seq.setReceiver(null); //Clear receiver so there's no connection here.
    }
    
    // <editor-fold defaultstate="collapsed" desc="Playlist specific functions">  
    
    private void enableNextPrev() {
        previousButton.setEnabled(!playlist.isFirstSong());
        nextButton.setEnabled(!playlist.isLastSong());
    }
    
    private void playlistEnded() {
        interruptNextSong = false;
        controlWindow.setStatus("Stopping...");
        seq.resetSequencer();
        startButton.setText(" ► ");
        startButton.setEnabled(false);
        sequenceProgressSlider.setValue(0);
        fileLoaded = false;
        controlWindow.setStatus("Stopped.");
    }
    
    private void clearPlaylist() {
        interruptNextSong = true;
        if (seq.isRunning()) {stopResetSequencer();} //I know this seems redundant, but I did not want to rewrite code and only wanted that part of the function
        playlist.clear();
        playlistEnded();        
        if (isConnected) {startButton.setEnabled(true);}
    }
    
    private void resetPlaylist() {
        interruptNextSong = true;
        if (seq.isRunning()) {stopResetSequencer();} //Same as above comment
        playlist.reset();
        playlistEnded();        
        if (isConnected) {startButton.setEnabled(true);}
    }

    private File getPlaylistFile(boolean direction) {
        String previouslyLoaded = app.prefs.get(Constants.PREF_LOADED_LIST, null);
        
        if (previouslyLoaded != null) {
            sequenceChooser.setCurrentDirectory(new File(previouslyLoaded));
        }
        sequenceChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        sequenceChooser.setFileFilter(MPLFilter);

        int returnVal;
        if(direction) {returnVal = sequenceChooser.showOpenDialog(this);}
        else {returnVal = sequenceChooser.showSaveDialog(this);}

        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File returnFile = sequenceChooser.getSelectedFile();
            app.prefs.put(Constants.PREF_LOADED_LIST, sequenceChooser.getSelectedFile().getPath());
            if(!direction) { //Make sure file ends in appropriate extension
                if(!returnFile.getAbsolutePath().endsWith(".mpl")) {returnFile = new File(sequenceChooser.getSelectedFile() + ".mpl");}
            }
            return returnFile;
        }
        return null;
    }
    
    private boolean savePlaylist(File f) {               
        if(playlist.savePlaylistFile(f)) {}
        else {return false;}
        return true;
    }
    
    private boolean loadPlaylist(File f) {        
        if(playlist.loadPlaylistFile(f)) {
            app.prefs.put(Constants.PREF_LOADED_MPL, f.getPath());
            if (isConnected && !playlist.isEmpty()) {startButton.setEnabled(true);}
        }
        else {return false;}        
        return true;
    }

    private void setupPlaylistTable() {        
        playlistTable.setModel(playlist);        
        playlistTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
        TableColumnModel ColumnModel = playlistTable.getColumnModel(); 
        
        ColumnModel.getColumn(0).setResizable(false);
        ColumnModel.getColumn(1).setResizable(false);        
                      
        ColumnModel.getColumn(0).setPreferredWidth(25);
        ColumnModel.getColumn(0).setMaxWidth(25);
        ColumnModel.getColumn(1).setPreferredWidth(55);        
        ColumnModel.getColumn(1).setMaxWidth(55);
                
    }// </editor-fold>      
}
