# -*- coding:UTF-8 -*-

import cv2
import threading
import time
from picamera import PiCamera
from datetime import datetime
import os
import subprocess
import json
import signal

class RaCamera:
     
    camera_active = False
    __recording_active = False
    camera_recording = False
    __frame = None
    __recordingThread=None
    __writer=None

    #recording_path="/home/admin/Video/"

    video_resulution_x = 1920
    video_resulution_y = 1080
    video_fps = 8.0
    video_duration = 30

    def __init__(self, Components):
        """
        Initialisiert das RaCamera

        :param Components: RaComponents Element
        :type Components: RaComponents
        """
        self.components = Components



    def startCamera(self):
        if self.camera_active==True:
            return
        print("Start Camera")
        self.camera_active = True
        self.__cameraThread = threading.Thread(target = self.threadCamera)
        self.lock = threading.Lock()
        print("- Starting Thread")
        self.__cameraThread.start()
        time.sleep(0.2)


    def stopCamera(self):
        if self.camera_active==False:
            return
        print("Stop Camera")
        self.camera_active = False
        print("- Wait for Thread ending")
        self.__cameraThread.join()
        print("- Stop recording")
        self.stopRecording()
        self.__frame = None


    def makePhoto(self, filename="test.jpg"):
        camera = PiCamera()
        camera.start_preview()
        sleep(5)
        camera.capture(filename)
        camera.stop_preview()


    def startRecording(self):
        if self.camera_recording == True:
            print("Recording already started")
            return
        print("Start Recording")
        self.camera_recording = True
        #self.startCamera()
        self.lock = threading.Lock()
        self.__recordingThread = threading.Thread(target = self.treadRecording)
        self.__recordingThread.start()

    
    def stopRecording(self):
        if self.camera_recording==False:
            print("Recording already stopped")
            return
        print("Stop Recording")

        if self.__recording_active == True:
            os.killpg(os.getpgid(self.record_process.pid), signal.SIGTERM)

        self.__recording_active = False
        self.camera_recording = False
        self.__recordingThread.join()


    def getFrame(self):
        return self.__frame


    def isActive(self):
        return self.camera_active


    def isRecording(self):
        return self.camera_recording


    def treadRecording__old(self):
        with self.lock:
            while self.camera_recording == True:
                startDate = datetime.today()
                startTime = time.perf_counter()
                ##fourcc = cv2.VideoWriter_fourcc(*'X264')
                #fourcc = cv2.VideoWriter_fourcc(*'mp4v')
                ##fourcc = cv2.VideoWriter_fourcc(*'xvid')
                ##fourcc = cv2.VideoWriter_fourcc(*'XVID')
                ##fourcc = cv2.VideoWriter_fourcc(*'MJPG')
                ##fourcc = cv2.VideoWriter_fourcc(*'DIVX')
                ##fourcc = cv2.VideoWriter_fourcc(*'WMV1')
                ##fourcc = cv2.VideoWriter_fourcc(*'WMV1')
                ##fourcc = cv2.VideoWriter_fourcc('X','V','I','D')
                filename = startDate.strftime("%Y-%m-%d_%H-%M-%S") + ".mp4"

                #print("- Video File Recording: "+self.recording_path+filename)
                #print("- FPS: "+str(self.video_fps))
                #print("- Resolution: "+str(self.video_resulution_x)+"x"+str(self.video_resulution_y))
                #
                #self.__writer = cv2.VideoWriter(self.recording_path+filename, fourcc, self.video_fps, (self.video_resulution_x, self.video_resulution_y))
                #self.__recording_active = True
                #
                #while self.camera_recording == True and self.__recording_active == True and time.perf_counter() - startTime < self.video_duration:
                #    time.sleep(1)
                #
                #print("- Video File closing")
                #self.__recording_active = False
                #time.sleep(0.5)
                #self.__writer.release()
                #if os.path.isfile(self.recording_path+filename) == False:
                #    print("NO VIDEO FILE FOUND")


    def treadRecording(self):
        maxVids = 5
        with self.lock:
            while self.camera_recording == True:
                startDate = datetime.today()
                startTime = time.perf_counter()
                filename = "/"+startDate.strftime("%Y-%m-%d_%H-%M-%S") + ".h264"
                # Record CommandLine
                # raspivid -o myvid.h264 -w 1280 -h 720 -b 8000000
                # -w,   --width       : Set image width <size>. Default 1920
                # -h,   --height      : Set image height <size>. Default 1080
                # -b,   --bitrate     : Set bitrate. Use bits per second
                #                       (e.g. 10MBits/s would be -b 10000000)
                # -o,   --output      : Output filename <filename>
                # -v,   --verbose     : Output verbose information during run
                # -t,   --timeout     : Duration of video (in ms)
                # -d,   --demo        : Demo mode(cycle through range of camera
                #                       options, no capture)
                # -fps, --framerate   : Specify the frames per second to record
                # -e,   --penc        : Display preview image *after* encoding
                #                       (shows compression artifacts)
                # -p, --preview       : Preview window settings <'x,y,w,h'>
                # -f, --fullscreen    : Fullscreen preview mode
                # -n, --nopreview     : Do not display a preview window
                # -sh, --sharpness    : Set image sharpness (-100 to 100)
                # -co, --contrast     : Set image contrast (-100 to 100)
                # -br, --brightness   : Set image brightness (0 to 100)
                # -sa, --saturation   : Set image saturation (-100 to 100)
                # -ISO, --ISO         : Set capture ISO
                # -vs, --vstab        : Turn on video stablisation
                # -ev, --ev           : Set EV compensation
                # -ex, --exposure     : Set exposure mode (see Notes)
                # -awb, --awb         : Set AWB mode (see Notes)
                # -ifx, --imxfx       : Set image effect (see Notes)
                # -cfx, --colfx       : Set colour effect (U:V)
                # -mm, --metering     : Set metering mode (see Notes)
                # -rot, --rotation    : Set image rotation (0, 90, 180, 270)
                # -hf, --hflip        : Set horizontal flip
                # -vf, --vflip        : Set vertical flip
                width = 1920
                height = 1080
                duration = 30000
                video_dir = "./"

                with open("config.json", "r") as file:
                    cfg = json.load(file)
                if "dir" in cfg["recording"]:
                    video_dir = cfg["recording"]["dir"]

                video_config = [
                    "raspivid",
                    "-o " + video_dir + filename,
                    "-n"
                ]
                self.appendRecordingConfig(cfg,video_config, "hf", "hflip", "bool")
                self.appendRecordingConfig(cfg,video_config, "vf", "vflip", "bool")
                self.appendRecordingConfig(cfg,video_config, "w", "width", "int", width)
                self.appendRecordingConfig(cfg,video_config, "h", "height", "int", height)
                self.appendRecordingConfig(cfg,video_config, "fps", "fps", "int")
                self.appendRecordingConfig(cfg,video_config, "b", "bitrate", "int")
                self.appendRecordingConfig(cfg,video_config, "t", "duration", "int", duration)
                self.appendRecordingConfig(cfg,video_config, "sh", "sharpness", "int")
                self.appendRecordingConfig(cfg,video_config, "co", "contrast", "int")
                self.appendRecordingConfig(cfg,video_config, "br", "brightness", "int")
                self.appendRecordingConfig(cfg,video_config, "sa", "saturation", "int")
                self.appendRecordingConfig(cfg,video_config, "vs", "stabilation", "bool")
                self.appendRecordingConfig(cfg,video_config, "ev", "EV", "int")
                self.appendRecordingConfig(cfg,video_config, "ex", "exposure", "string")
                self.appendRecordingConfig(cfg,video_config, "awb", "awb", "string")
                self.appendRecordingConfig(cfg,video_config, "ifx", "imxfx", "string")
                self.appendRecordingConfig(cfg,video_config, "cfx", "colfx", "string")
                self.appendRecordingConfig(cfg,video_config, "mm", "metering", "string")
                self.appendRecordingConfig(cfg,video_config, "rot", "rotation", "int")
                self.appendRecordingConfig(cfg,video_config, "fli", "flicker", "int")
                self.appendRecordingConfig(cfg,video_config, "ss", "shutterspeed", "int")
                self.appendRecordingConfig(cfg,video_config, "drc", "dynamicRangeCompression", "int")
                
                #if("hflip" in cfg["recording"]):
                #    if(cfg["recording"]["hflip"]==True):
                #        video_config.append("-hf")
                #if("vflip" in cfg["recording"]):
                #    if(cfg["recording"]["vflip"]==True):
                #        video_config.append("-vf")
                #if("duration" in cfg["recording"]):
                #    if(cfg["recording"]["duration"]!="" and cfg["recording"]["duration"]!=False):
                #        duration = cfg["recording"]["duration"]
                #video_config.append("-t "+duration)
                #if("width" in cfg["recording"]):
                #    if(cfg["recording"]["width"]!="" and cfg["recording"]["width"]!=False):
                #        width = cfg["recording"]["width"]
                #video_config.append("-w "+width)
                #if("height" in cfg["recording"]):
                #    if(cfg["recording"]["height"]!="" and cfg["recording"]["height"]!=False):
                #        height = cfg["recording"]["height"]
                #video_config.append("-h "+height)
                #if("fps" in cfg["recording"]):
                #    if(cfg["recording"]["fps"]!="" and cfg["recording"]["fps"]!=False):
                #        video_config.append("-fps "+cfg["recording"]["fps"])
                #if("bitrate" in cfg["recording"]):
                #    if(cfg["recording"]["bitrate"]!="" and cfg["recording"]["bitrate"]!=False):
                #        video_config.append("-b "+cfg["recording"]["bitrate"])
                #if("sharpness" in cfg["recording"]):
                #    if(cfg["recording"]["sharpness"]!="" and cfg["recording"]["sharpness"]!=False):
                #        video_config.append("-sh "+cfg["recording"]["sharpness"])
                #if("contrast" in cfg["recording"]):
                #    if(cfg["recording"]["contrast"]!="" and cfg["recording"]["contrast"]!=False):
                #        video_config.append("-co "+cfg["recording"]["contrast"])
                #if("brightness" in cfg["recording"]):
                #    if(cfg["recording"]["brightness"]!="" and cfg["recording"]["brightness"]!=False):
                #        video_config.append("-br "+cfg["recording"]["brightness"])
                #if("saturation" in cfg["recording"]):
                #    if(cfg["recording"]["saturation"]!="" and cfg["recording"]["saturation"]!=False):
                #        video_config.append("-sa "+cfg["recording"]["saturation"])
                #if("stabilation" in cfg["recording"]):
                #    if(cfg["recording"]["stabilation"]==True):
                #        video_config.append("-vs")
                #if("exposure" in cfg["recording"]):
                #    if(cfg["recording"]["exposure"]!="" and cfg["recording"]["exposure"]!=False):
                #        video_config.append("-ex "+cfg["recording"]["exposure"])
                #if("awb" in cfg["recording"]):
                #    if(cfg["recording"]["awb"]!="" and cfg["recording"]["awb"]!=False):
                #        video_config.append("-awb "+cfg["recording"]["awb"])
                #if("imxfx" in cfg["recording"]):
                #    if(cfg["recording"]["imxfx"]!="" and cfg["recording"]["imxfx"]!=False):
                #        video_config.append("-ifx "+cfg["recording"]["imxfx"])
                #if("metering" in cfg["recording"]):
                #    if(cfg["recording"]["metering"]!="" and cfg["recording"]["metering"]!=False):
                #        video_config.append("-mm "+cfg["recording"]["metering"])
                #if("rotation" in cfg["recording"]):
                #    if(cfg["recording"]["rotation"]!="" and cfg["recording"]["rotation"]!=False):
                #        video_config.append("-rot "+cfg["recording"]["rotation"])

                print("StartRecording")
                print(video_config)
                cmd = ' '.join(video_config)
                print(cmd)
                self.__recording_active = True
                self.record_process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
                p_status = self.record_process.communicate()
                self.__recording_active = False
                maxVids-=1
                if maxVids==0:
                    self.__recording_active = False
                    self.camera_recording = False


    def appendRecordingConfig(self, cfg, video_config, argument:str, propertyName: str, t : str = "string", default = ""):
        if t=="string" or t=="s" or t=="str":
            if propertyName in cfg["recording"]:
                v = cfg["recording"][propertyName]
                if isinstance(v, str)==True:
                    if v!="":
                        video_config.append("-"+argument+" "+v)
                if isinstance(v, int):
                    video_config.append("-"+argument+" "+str(v))
                if isinstance(v, float):
                    video_config.append("-"+argument+" "+str(v))
                if isinstance(v, bool):
                    if v==True:
                        video_config.append("-"+argument+" 1")
                return

        elif t=="int" or t=="i" or t=="integer":
            if propertyName in cfg["recording"]:
                v = cfg["recording"][propertyName]
                if isinstance(v, int)==True:
                    video_config.append("-"+argument+" "+str(v))
                if isinstance(v, float)==True:
                    video_config.append("-"+argument+" "+str(v))
                elif isinstance(v, str)==True:
                    video_config.append("-"+argument+" "+v)
                elif isinstance(v, bool)==True:
                    if v==True:
                        video_config.append("-"+argument+" 1")
                return

        elif t=="bool" or t=="b" or b=="boolean":
            if propertyName in cfg["recording"]:
                v = cfg["recording"][propertyName]
                if isinstance(v, bool)==True:
                    if v==True:
                        video_config.append("-"+argument)
                elif isinstance(v, int)==True:
                    if v>0:
                        video_config.append("-"+argument)
                        return
                elif isinstance(v, float)==True:
                    if v>0:
                        video_config.append("-"+argument)
                        return
                elif isinstance(v, str)==True:
                    if v!="":
                        video_config.append("-"+argument)
                return

        if isinstance(default, str)==True:
            if default!="":
                video_config.append("-"+argument+" "+default)
        elif isinstance(default, int):
            video_config.append("-"+argument+" "+str(default))
        elif isinstance(default, float):
            video_config.append("-"+argument+" "+str(default))
        elif isinstance(default, bool):
            if default==True:
                video_config.append("-"+argument)

    def threadCamera(self):
        with self.lock:
            print("Video Res: " + str(self.video_resulution_x) + "x"+str(self.video_resulution_y))
            cap = cv2.VideoCapture(0)
            cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.video_resulution_x)
            cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.video_resulution_y)
            #cap.set(cv2.CAP_PROP_FPS, self.video_fps)
            if not cap.isOpened():
                print("Cannot open camera")
                self.camera_active = False
                return

            success,image = cap.read()

            #camera = PiCamera()
            #camera.resolution = (self.video_resulution_x, self.video_resulution_y)
            #camera.contrast = 10
            #camera.image_effect = "watercolor"
            
            while self.camera_active:
                ret, frame = cap.read()
                #cv2.imread("Frame", frame)
                if ret:
                    self.__frame = frame
                    #if self.__recording_active==True:
                        #self.__writer.write(frame)
            print("- Release Camera")
            cap.release()
            cv2.destroyAllWindows()