#!/usr/bin/env python
# -*- coding: utf-8 -*-

from concurrent.futures import thread
import cv2
import RPi.GPIO as GPIO
import LCD_1in44
import LCD_Config
from datetime import date
import time
import threading
import json

from PIL import Image,ImageDraw,ImageFont,ImageColor


class mainCls:

    video_resulution_x = 1920
    video_resolution_y = 1080
    video_frames = 30.0
    video_length = 90

    display_resolution_x = 128
    display_resolution_y = 128
    display_frames = 5

    camera_id = 0

    recording = False
    recordingActive = False
    displaying = False
    showMenu = False
    currentMenuItem = [0]


    KEY_UP_PIN     = 6 
    KEY_DOWN_PIN   = 19
    KEY_LEFT_PIN   = 5
    KEY_RIGHT_PIN  = 26
    KEY_PRESS_PIN  = 13
    KEY1_PIN       = 21
    KEY2_PIN       = 20
    KEY3_PIN       = 16

    

    #################################################
    ##   Init & Setup
    #################################################
    def __init__(self):
        self.lock = threading.Lock()
        self.setupDisplay()
        #splash = threading.Thread(target = self.showLogo)
        #splash.start()
        self.showLogo()
        self.setupMenu()
        self.setupKeypad()
        #self.setupCamera()
        #splash.join()


    def run(self):
        while True:
            time.sleep(0.1)

        

    def setupKeypad(self):
        GPIO.cleanup()
        GPIO.setmode(GPIO.BCM) 
        GPIO.setup(self.KEY_UP_PIN,      GPIO.IN, pull_up_down=GPIO.PUD_UP)    # Input with pull-up
        GPIO.setup(self.KEY_DOWN_PIN,    GPIO.IN, pull_up_down=GPIO.PUD_UP)  # Input with pull-up
        GPIO.setup(self.KEY_LEFT_PIN,    GPIO.IN, pull_up_down=GPIO.PUD_UP)  # Input with pull-up
        GPIO.setup(self.KEY_RIGHT_PIN,   GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
        GPIO.setup(self.KEY_PRESS_PIN,   GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up
        GPIO.setup(self.KEY1_PIN,        GPIO.IN, pull_up_down=GPIO.PUD_UP)      # Input with pull-up
        GPIO.setup(self.KEY2_PIN,        GPIO.IN, pull_up_down=GPIO.PUD_UP)      # Input with pull-up
        GPIO.setup(self.KEY3_PIN,        GPIO.IN, pull_up_down=GPIO.PUD_UP)      # Input with pull-up
        self.keyboardThread = threading.Thread(target=self.threadCheckKeypad, daemon=True)
        self.keyboardThread.start()

    def showLogo(self):
        image = Image.open('img/logo.bmp')
        self.disp.LCD_ShowImage(image,0,0)
        time.sleep(2.4)

    def setupDisplay(self):
        self.disp = LCD_1in44.LCD()
        Lcd_ScanDir = LCD_1in44.SCAN_DIR_DFT  #SCAN_DIR_DFT = D2U_L2R
        self.disp.LCD_Init(Lcd_ScanDir)
        self.disp.LCD_Clear()

    def setupMenu(self):
        with open("menu.json", "r") as read_file:
            self.menu = json.load(read_file)

    def renderDisplay(self):
        if self.showMenu:
            mnuItem = self.getCurrentMenuItem()
            image = Image.new("RGB", (self.display_resolution_x, self.display_resolution_y), "BLACK")
            if "icon" in mnuItem:
                image = Image.open('img/'+mnuItem["icon"])
            draw = ImageDraw.Draw(image)
            draw.rectangle([(17,99),(112,22)],fill = "BLUE")
            draw.rectangle([(18,100),(110,20)],fill = "BLACK")
            if "displayName" in mnuItem:
                draw.text((23, 101), mnuItem["displayName"], fill = "BLUE")
            self.disp.LCD_ShowImage(image,0,0)

        elif self.displaying == True and self.frame is not None:
            resized = cv2.resize(self.frame, (self.display_resolution_x, self.display_resolution_y)) 
            self.disp.LCD_ShowImage(resized,0,0)

        else:
            pass



    #################################################
    ##   Camera
    #################################################
    def startCamera(self):
        self.camera_active = True
        self.cameraThread = threading.Thread(target=self.threadCamera)
        self.cameraThread.start()

    def stopCamera(self):
        self.self.camera_active = False
        self.cameraThread.join()

    def threadCamera(self):
        cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.video_resulution_x)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.video_resulution_y)
        while self.camera_active:
            ret, frame = cap.read()
            if not ret:
                self.frame = frame
                if self.displaying==True:
                    self.renderDisplay()
                if self.recordingActive==True:
                    self.writer.write(frame)
        cap.release()
        cv2.destroyAllWindows()


    #################################################
    ##   Recording
    #################################################
    def startRecording(self):
        self.recording = True
        while self.recording:
            recordThread=threading.Thread(target=self.threadRecordVideo)
            recordThread.start()
            recordThread.join()

    def threadRecordVideo(self):
        startDate = date.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')
        filename = startDate.strftime("%Y-%m-%d_%H-%M-%S") + ".tmp"
        self.writer = cv2.VideoWriter("/home/admin/Video/"+filename, fourcc, self.video_frames, (self.video_resulution_x, self.video_resolution_y))
        self.recordingActive = True
        time.sleep(self.video_length)
        self.recordingActive = False
        time.sleep(0.1)
        self.writer.release()

    #################################################
    ##   Keys
    #################################################
    def onKeyPressed(self, key, duration):
        if key==self.KEY3_PIN:
            if duration<2:
                self.displaying = False
        if key==self.KEY_LEFT_PIN:
            if len(self.currentMenuItem) <= 1:
                self.showMenu=False
                self.currentMenuItem = [0]
            else:
                self.currentMenuItem.list = self.currentMenuItem.list[ : -1]
        if key==self.KEY_RIGHT_PIN:
            mnuItem = self.getCurrentMenuItem()
            if "action" in mnuItem:
                if "." in mnuItem["action"]:
                    func = getattr(mnuItem["action"].split(".")[0],mnuItem["action"].split(".")[1])
                    func()
                else:
                    func = getattr(self,mnuItem["action"])
                    func()
            if "sub" in mnuItem:
                self.currentMenuItem.append(0)
        if key==self.KEY_UP_PIN:
            if self.currentMenuItem[-1]>0:
                self.currentMenuItem[-1] = self.currentMenuItem[-1] - 1
        if key==self.KEY_DOWN_PIN:
            mnu = self.getMenuItem(self.currentMenuItem)
            maxMnu = len(mnu)
            if self.currentMenuItem[-1]<mnu:
                self.currentMenuItem[-1] = self.currentMenuItem[-1] + 1
        if key==self.KEY_PRESS_PIN:
            if self.showMenu==True:
                self.showMenu=False
            else:
                self.showMenu=True

        self.renderDisplay()
            


    def onKeyDown(self, key):
        if key==self.KEY3_PIN:
            self.displaying = True
        if key==self.KEY1_PIN:
            if self.startRecording==True:
                self.startRecording = False
            else:
                self.startRecording()

    def onKeyUp(self, key):
        pass



    #################################################
    ##   Menu
    #################################################
    def getMenuItem(self, index):
        return self.__getMenuItemSub(self.menu,index, 0)

    def getCurrentMenuItem(self):
        mnu = self.__getMenuItemSub(self.menu, self.currentMenuItem,0)
        return mnu[self.currentMenuItem[-1]]

    def __getMenuItemSub(self, mnu,index,i):
        length = len(index)
        if i<=length-1 and "sub" in mnu[index[i]]:
            return self.__getMenuItemSub(mnu[index[i]]["sub"],index,i+1)
        return mnu
        



    #################################################
    ##   Keypad Thread
    #################################################
    key1_pressed=False
    key2_pressed=False
    key3_pressed=False
    keyUp_pressed=False
    keyDown_pressed=False
    keyLeft_pressed=False
    keyRight_pressed=False
    keyPress_pressed=False

    key1_dur=None
    key2_dur=None
    key3_dur=None
    keyUp_dur=None
    keyDown_dur=None
    keyLeft_dur=None
    keyRight_dur=None
    keyPress_dur=None

    def threadCheckKeypad(self):
        while True:
            self.checkKeyPressed()

    def checkKeyPressed(self):
        # Key1
        if GPIO.input(self.KEY1_PIN) == 0:
            if self.key1_pressed==True:
                self.key1_pressed=False
                self.onKeyUp(self.KESY1.PIN)
                self.onKeyPress(self.KEY1_PIN, time.perf_counter() - self.key1_dur)
                self.key1_dur=None
        else:
            if self.key1_pressed==False:
                self.onKeyDown(self.KEY1_PIN)
                self.key1_dur=time.perf_counter()
                self.key1_pressed=True

        # Key2
        if GPIO.input(self.KEY2_PIN) == 0:
            if self.key2_pressed==True:
                self.key2_pressed=False
                self.onKeyUp(self.KESY2.PIN)
                self.onKeyPress(self.KEY2_PIN, time.perf_counter() - self.key2_dur)
                self.key2_dur=None
        else:
            if self.key2_pressed==False:
                self.onKeyDown(self.KEY2_PIN)
                self.key2_dur=time.perf_counter()
                self.key2_pressed=True

        # Key3
        if GPIO.input(self.KEY3_PIN) == 0:
            if self.key3_pressed==True:
                self.key3_pressed=False
                self.onKeyUp(self.KESY3_PIN)
                self.onKeyPress(self.KEY3_PIN, time.perf_counter() - self.key3_dur)
                self.key3_dur=None
        else:
            if self.key3_pressed==False:
                self.onKeyDown(self.KEY3_PIN)
                self.key3_dur=time.perf_counter()
                self.key3_pressed=True

        # Key Up
        if GPIO.input(self.KEY_UP_PIN) == 0:
            if self.keyUp_pressed==True:
                self.keyUp_pressed=False
                self.onKeyUp(self.KESY2.PIN)
                self.onKeyPress(self.KEY_UP_PIN, time.perf_counter() - self.keyUp_dur)
                self.keyUp_dur=None
        else:
            if self.keyUp_pressed==False:
                self.onKeyDown(self.KEY_UP_PIN)
                self.keyUp_dur=time.perf_counter()
                self.keyUp_pressed=True

        # Key Down
        if GPIO.input(self.KEY_DOWN_PIN) == 0:
            if self.keyDown_pressed==True:
                self.keyDown_pressed=False
                self.onKeyUp(self.KESY2.PIN)
                self.onKeyPress(self.KEY_DOWN_PIN, time.perf_counter() - self.keyDown_dur)
                self.keyDown_dur=None
        else:
            if self.keyDown_pressed==False:
                self.onKeyDown(self.KEY_DOWN_PIN)
                self.keyDown_dur=time.perf_counter()
                self.keyDown_pressed=True

        # Key Left
        if GPIO.input(self.KEY_LEFT_PIN) == 0:
            if self.keyLeft_pressed==True:
                self.keyLeft_pressed=False
                self.onKeyUp(self.KESY2.PIN)
                self.onKeyPress(self.KEY_LEFT_PIN, time.perf_counter() - self.keyLeft_dur)
                self.keyLeft_dur=None
        else:
            if self.keyLeft_pressed==False:
                self.onKeyDown(self.KEY_LEFT_PIN)
                self.keyLeft_dur=time.perf_counter()
                self.keyLeft_pressed=True

        # Key Right
        if GPIO.input(self.KEY_RIGHT_PIN) == 0:
            if self.keyRight_pressed==True:
                self.keyRight_pressed=False
                self.onKeyUp(self.KESY2.PIN)
                self.onKeyPress(self.KEY_RIGHT_PIN, time.perf_counter() - self.keyRight_dur)
                self.keyRight_dur=None
        else:
            if self.keyRight_pressed==False:
                self.onKeyDown(self.KEY_RIGHT_PIN)
                self.keyRight_dur=time.perf_counter()
                self.keyRight_pressed=True

        # Key Press
        if GPIO.input(self.KEY_PRESS_PIN) == 0:
            if self.keyPress_pressed==True:
                self.keyPress_pressed=False
                self.onKeyUp(self.KESY2.PIN)
                self.onKeyPress(self.KEY_PRESS_PIN, time.perf_counter() - self.keyPress_dur)
                self.keyPress_dur=None
        else:
            if self.keyPress_pressed==False:
                self.onKeyDown(self.KEY_PRESS_PIN)
                self.keyPress_dur=time.perf_counter()
                self.keyPress_pressed=True


if __name__ == "__main__":
    app = mainCls()
    app.run()