class Image_recorder:
    def __init__(self, media):
        self.writer = None
        self.media = media
        self.config = Configuration()
        self.file_name = None
        self.index = 0

    def start(self, shape, path=None, fps=30):
        # TODO manage multiple record
        # manage only one record at time
        if self.writer:
            self.stop()

        if not path:
            path = "%s" % (self.config.get_path_save_record())
            if not path:
                path = "./"
        elif "/" not in path:
            path = "%s%s" % (self.config.get_path_save_record(), path)

        if os.path.isfile(path):
            log.print_function(logger.error, "File already exist %s" % path)
            return False

        if not os.path.isdir(path):
            try:
                os.makedirs(path)
            except:
                pass

        self.file_name = path
        logger.info("Start record on path: %s", path)

        self.media.add_observer(self.write)
        self.writer = self.write
        return True

    def next_filename(self):
        path = os.path.join(self.file_name, str(self.index).zfill(10) + '.png')
        self.index += 1
        return path

    def write(self, image):
        cv2.imwrite(self.next_filename(), image)

    def get_file_name(self):
        if not self.file_name:
            return ""
        return self.file_name

    def stop(self):
        logger.info("Close record on path: %s", self.file_name)
        self.file_name = None
        if not self.writer:
            return False
        self.media.remove_observer(self.write)
        self.writer = None
        return True
class Video_recorder:
    def __init__(self, media):
        self.writer = None
        self.media = media
        self.config = Configuration()
        self.file_name = None

    def start(self, shape, path=None, fps=30):
        # TODO manage multiple record
        # manage only one record at time
        if self.writer:
            self.stop()
        add_format_name = False
        if path:
            # exception, if not contain /, maybe it's just a filename
            if "/" not in path:
                name = "%s%s.avi" % (self.config.get_path_save_record(), path)
            else:
                # TODO need to add extension when giving all path with filename?
                name = path
                if os.path.isdir(path):
                    add_format_name = True
        else:
            add_format_name = True
            # TODO mkdir if directory
            name =  self.config.get_path_save_record()
        if add_format_name:
            name += "%s.avi" % time.strftime("%Y_%m_%d_%H_%M_%S", time.gmtime())

        if os.path.isfile(name):
            log.print_function(logger.error, "File already exist %s" % name)
            return False

        self.file_name = name
        logger.info("Start record on path: %s", name)

        fps = 8
        # fourcc = cv.CV_FOURCC('D','I','V','X')
        # fourcc = cv.CV_FOURCC('F', 'L', 'V', '1')
        # fourcc = cv.CV_FOURCC('V', 'P', '8', '0') # not work
        # fourcc = cv.CV_FOURCC('M', 'J', 'P', 'G')
        # fourcc = cv.CV_FOURCC('D', 'I', 'B', ' ')  # Uncompressed RGB, 24 or 32 bit  - not working linux
        fourcc = cv.CV_FOURCC('I', 'Y', 'U', 'V')  # Uncompressed YUV, 4:2:0 chroma subsampled , same of 'I420'
        self.writer = cv2.VideoWriter(filename=name, fourcc=fourcc, fps=fps, frameSize=shape, isColor=1)
        self.writer.open(name, fourcc, fps, shape, 1)
        self.media.add_observer(self.writer.write)
        return True

    def get_file_name(self):
        if not self.file_name:
            return ""
        return self.file_name

    def stop(self):
        logger.info("Close record on path: %s", self.file_name)
        self.file_name = None
        if not self.writer:
            return False
        self.media.remove_observer(self.writer.write)
        del self.writer
        self.writer = None
        return True
class ImageRecorder:

    def __init__(self, media):
        self.writer = None
        self.media = media
        self.config = Configuration()
        self.file_name = None
        self.index = 0
        self.compress = 0

    def start(self, shape, path=None, fps=30, compress=0):
        # TODO manage multiple record
        # manage only one record at time
        if self.writer:
            self.stop()

        if not path:
            path = "%s" % (self.config.get_path_save_record())
            if not path:
                path = "./"
        elif "/" not in path:
            path = "%s%s" % (self.config.get_path_save_record(), path)

        if os.path.isfile(path):
            log.print_function(logger.error, "File already exist %s" % path)
            return False

        self.compress = compress

        if not os.path.isdir(path):
            try:
                os.makedirs(path)
            except:
                pass

        self.file_name = path
        logger.info("Start record on path: %s", path)

        self.media.add_observer(self.write)
        self.writer = self.write
        return True

    def next_filename(self):
        path = os.path.join(self.file_name, str(self.index).zfill(10) + '.png')
        self.index += 1
        return path

    def write(self, image):
        compress = int(self.compress * 0.09)
        params = [cv2.cv.CV_IMWRITE_PNG_COMPRESSION, compress]
        cv2.imwrite(self.next_filename(), image, params)

    def get_file_name(self):
        if not self.file_name:
            return ""
        return self.file_name

    def stop(self):
        logger.info("Close record on path: %s", self.file_name)
        self.file_name = None
        if not self.writer:
            return False
        self.media.remove_observer(self.write)
        self.writer = None
        return True
class VideoRecorder:
    def __init__(self, media):
        self.writer = None
        self.media = media
        self.config = Configuration()
        self.file_name = None
        self.process = None
        # create a semaphore to protect when closing ffmpeg
        self.sem = Semaphore(1)

    def start(self, shape, path=None, fps=30, compress=0):
        # TODO manage multiple record
        # manage only one record at time
        if self.process:
            self.stop()
        add_format_name = False
        if path:
            # exception, if not contain /, maybe it's just a filename
            if "/" not in path:
                name = "%s%s.avi" % (self.config.get_path_save_record(), path)
            else:
                # TODO need to add extension when giving all path with
                # filename?
                name = path
                if os.path.isdir(path):
                    add_format_name = True
        else:
            add_format_name = True
            # TODO mkdir if directory
            name = self.config.get_path_save_record()
        if add_format_name:
            name += "%s.avi" % time.strftime(
                "%Y_%m_%d_%H_%M_%S",
                time.gmtime())

        if os.path.isfile(name):
            log.print_function(logger.error, "File already exist %s" % name)
            return False

        self.file_name = name
        logger.info("Start record on path: %s", name)

        # 1 is best quality, 36 is worse
        qscale = compress * 0.35 + 1
        self.process = Popen(
            ['ffmpeg', '-y', '-f', 'image2pipe', '-vcodec', 'mjpeg', '-r',
             '24',
             '-i', '-', '-vcodec', 'mpeg4', '-qscale', "%s" % qscale, '-r',
             '24', name], stdin=PIPE)
        self.media.add_observer(self.add_image)
        return True

    def add_image(self, image):
        # take sem with blocking
        self.sem.acquire(True)
        # check if process is active after the sem
        if self.process is None:
            self.sem.release()
            return
        # convert image to rgb in image2
        image2 = np.asarray(image, dtype="uint8")
        cv2.cvtColor(image, cv.CV_BGR2RGB, image2)
        # convert in PIL image
        img = Image.fromarray(image2, 'RGB')
        # Save it in ffmpeg process
        img.save(self.process.stdin, 'JPEG')
        self.sem.release()

    def get_file_name(self):
        return self.file_name if self.file_name else ""

    def stop(self):
        logger.info("Close record on path: %s", self.file_name)
        self.file_name = None
        if not self.process:
            return False
        self.media.remove_observer(self.add_image)
        self.sem.acquire(True)
        self.process.stdin.close()
        self.process.wait()
        self.process = None
        self.sem.release()
        return True