'''wrapping the code inside a function
so that the imports of sound manager and audio commands are not loaded in parallel processing process
but this will work only in windows as linux creates a process using fork which will copy the whole process
so there  it cannot be stopped

also in windows this script will be executed again in case the script which uses this library has imported the detector outside
   if __name__ == "__main__" condition as that script will execute leading to create the copy
so to avoid that whole code in wrapped in function

again on linux this will not be the case as it will fork and start its execution from next line


lastly if the script which uses this library has imported the detector inside that (if name == main ) condition then  this whole library   will not be executed again
in that case only the  variables and data which that script have will be executed again so be careful
'''

def getDetector():
    import cv2
    import threading
    from .SoundSystem.SoundManager import sound_manager
    from .SoundSystem.AudioCommands import CommandListener
    from multiprocessing import Queue
    from .Models.ParallelProcessing import Worker


    class drowsiness_detector(threading.Thread):

        __FONT =  cv2.FONT_HERSHEY_COMPLEX_SMALL

        def __init__(self, audio=None, UseAssistant=False):
            super().__init__()
            self.__stream = cv2.VideoCapture(0)
            self.__MySoundManager = sound_manager(audio=audio)
            self.__Assistant = None
            self.__input_queue = Queue() # used for sending frame to worker
            self.__result_queue = Queue() # used for receiving prediction results from worker
            self.__worker = Worker(input_frames=self.__input_queue, result_queue=self.__result_queue)
            self.__worker.start()
            self.__LastWorkerResult = None
            self.__Interrupt = False
            if UseAssistant:
                self.__Assistant = CommandListener(self)
                self.__Assistant.start()

        def setSensitivity(self, sensitivity):
            self.__MySoundManager.setSensitivity(sensitivity)

        def __getFrame(self):
            retrieved, frame = self.__stream.read()
            if not retrieved:
                print("error occurred while capturing video stream")
                return None
            return frame



        def __display_frame(self, frame):

            if self.__LastWorkerResult is not None:
                for eye in [self.__LastWorkerResult.LeftEye, self.__LastWorkerResult.RightEye]:
                     if eye is not None:
                         x, y, w, h = eye
                         cv2.rectangle(frame, (x, y), (x + w, y + h), (100, 100, 100), 1)
                         message = "closed" if self.__LastWorkerResult.OpenProbability == 0 else "open"
                         self.__putMessage(message, frame)
                if self.__LastWorkerResult.LeftEye is None and self.__LastWorkerResult.RightEye is None:
                         self.__putMessage("Eyes not detected", frame)
            else:
                self.__putMessage("Initializing .......",frame=frame)

            cv2.imshow('frame', frame)

            # waiting for 1ms before proceeding further
            if cv2.waitKey(1) & 0xFF == ord('q'):
                return False
            return True

        def __putMessage(self,message,frame):
            cv2.putText(frame, message, (10, frame.shape[:2][0] - 20), self.__class__.__FONT, 1, (255, 255, 255), 1,
                        cv2.LINE_AA)

        def run(self):
            while True:
                frame = self.__getFrame()
                if frame is None:
                    continue

                if self.__input_queue.empty():
                    self.__input_queue.put(frame)

                if not self.__result_queue.empty():
                    self.__LastWorkerResult = self.__result_queue.get()
                    self.__MySoundManager.handle_sound(self.__LastWorkerResult.OpenProbability)

                if not self.__display_frame(frame)  or self.__Interrupt:
                    break

            self.__stream.release()
            self.__MySoundManager.interrupt()
            if self.__Assistant is not None:
                self.__Assistant.stop()
            self.__worker.terminate()
            cv2.destroyAllWindows()

        def quit(self):
            self.__Interrupt = True

    return drowsiness_detector

