package com.salcedo.rapbot.object;

import akka.actor.ActorSystem;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import com.salcedo.rapbot.object.jukebox.JukeBox;
import com.salcedo.rapbot.object.jukebox.JukeBoxes;
import org.opencv.core.Core;
import uk.co.caprica.vlcj.component.EmbeddedMediaPlayerComponent;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;

import static javax.swing.SwingUtilities.invokeLater;
import static javax.swing.UIManager.setLookAndFeel;

public final class ObjectDetectorTest extends WindowAdapter {
    private static final String APP_NAME = "FaceDetect";
    private final LoggingAdapter log;
    private final ObjectDetector objectDetector;
    private final JFrame frame;
    private final JukeBox jukeBox;
    private final EmbeddedMediaPlayerComponent playerComponent;

    private ObjectDetectorTest(final Path musicLibrary) {
        final ActorSystem system = ActorSystem.create(APP_NAME);

        this.objectDetector = ObjectDetectors.openCV(system);
        this.frame = new JFrame(APP_NAME);
        this.log = Logging.getLogger(system, this);
        this.playerComponent = new EmbeddedMediaPlayerComponent();
        this.jukeBox = JukeBoxes.create(system, musicLibrary, this.playerComponent);
    }

    public static void main(final String[] args) throws Exception {
        setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        final Path musicLibrary = Paths.get("~", "Downloads");
        final ObjectDetectorTest objectDetectorTest = new ObjectDetectorTest(musicLibrary);
        invokeLater(objectDetectorTest::run);
    }

    @Override
    public void windowClosing(final WindowEvent e) {
        this.log.info("Terminating application.");
        this.jukeBox.turnOff();
        System.exit(0);
    }

    private void run() {
        this.log.info("Running Face Detect Demo. JukeBox: {}", this.jukeBox);

        initializeFrame();

        detectLoop();
    }

    private void detectLoop() {
        while (true) {
            try {
                detectFaceAndPlayMusic();
            } catch (final Exception e) {
                e.printStackTrace();
                sleep();
            }
        }
    }

    private void detectFaceAndPlayMusic() {
        if (this.jukeBox.isPlayingMusic()) {
            sleep();
        } else {
            if (this.objectDetector.objectDetected()) {
                this.log.info("Face detected.");
                this.jukeBox.playNextSong();
            } else {
                this.log.info("No face detected. JukeBox: {}", this.jukeBox);
                sleep();
            }
        }
    }

    private void sleep() {
        try {
            Thread.sleep(TimeUnit.SECONDS.toMillis(5L));
        } catch (final InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void initializeFrame() {
        final JToggleButton pauseButton = new JToggleButton("Pause/Resume");
        final JButton previousButton = new JButton("Previous");
        final JButton nextButton = new JButton("Next");

        final JPanel controlsPane = new JPanel();
        controlsPane.add(pauseButton);
        controlsPane.add(previousButton);
        controlsPane.add(nextButton);

        final JPanel contentPane = new JPanel();
        contentPane.setLayout(new BorderLayout());
        contentPane.add(this.playerComponent, BorderLayout.CENTER);
        contentPane.add(controlsPane, BorderLayout.SOUTH);

        pauseButton.addActionListener(event -> this.jukeBox.pauseOrResume());
        previousButton.addActionListener(event -> this.jukeBox.playPreviousSong());
        nextButton.addActionListener(event -> this.jukeBox.playNextSong());

        this.frame.setContentPane(contentPane);
        this.frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        this.frame.setBounds(100, 100, 600, 400);
        this.frame.addWindowListener(this);
        this.frame.setVisible(true);
    }
}

@@ -487,16 +487,109 @@
 .Paths;%0A
+import java.util.concurrent.Executors;%0Aimport java.util.concurrent.ScheduledExecutorService;%0A
 import j
@@ -845,16 +845,130 @@
 etect%22;%0A
+    private final static ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();%0A
     priv
@@ -1860,22 +1860,35 @@
 et(%22
-~%22, %22Downloads
+/usr%22, %22src%22, %22app%22, %22Music
 %22);%0A
@@ -1979,16 +1979,17 @@
 brary);%0A
+%0A
         
@@ -2020,19 +2020,66 @@
 orTest::
+initializeFrame);%0A%0A        objectDetectorTest.
 run
+(
 );%0A    %7D
@@ -2377,47 +2377,86 @@
     
-initializeFrame();%0A%0A        detectLoop(
+executorService.scheduleAtFixedRate(this::detectLoop, 0L, 5L, TimeUnit.SECONDS
 );%0A 
@@ -2497,35 +2497,8 @@
 ) %7B%0A
-        while (true) %7B%0A    
     
@@ -2499,36 +2499,32 @@
 %7B%0A        try %7B%0A
-    
             dete
@@ -2549,28 +2549,24 @@
 ();%0A        
-    
 %7D catch (fin
@@ -2587,36 +2587,32 @@
 ) %7B%0A            
-    
 e.printStackTrac
@@ -2620,47 +2620,8 @@
 ();%0A
-                sleep();%0A            %7D%0A
     
@@ -2726,39 +2726,38 @@
 ) %7B%0A            
-sleep()
+return
 ;%0A        %7D else
@@ -2747,36 +2747,26 @@
 n;%0A        %7D
- else %7B%0A    
+%0A%0A
         if (
@@ -2809,36 +2809,32 @@
 ) %7B%0A            
-    
 this.log.info(%22F
@@ -2858,28 +2858,24 @@
             
-   
- 
 this.jukeBox
@@ -2899,20 +2899,16 @@
         
-    
 %7D else %7B
@@ -2912,36 +2912,32 @@
 e %7B%0A            
-  
-  
 this.log.info(%22N
@@ -2994,245 +2994,10 @@
     
-        sleep();%0A            %7D%0A        %7D%0A    %7D%0A%0A    private void sleep() %7B%0A        try %7B%0A            Thread.sleep(TimeUnit.SECONDS.toMillis(5L));%0A        %7D catch (final InterruptedException e) %7B%0A            e.printStackTrace();%0A        
 %7D
+%0A
 %0A   
@@ -3052,22 +3052,16 @@
  final J
-Toggle
 Button p
@@ -3082,14 +3082,8 @@
 ew J
-Toggle
 Butt

Fix rendering issues and uses scheduled executor service instead of infinite loop.