import tkinter as tk
import cv2
from PIL import Image, ImageTk
from IPython.display import clear_output
import IPython
import serial, time




# Set camera resolution.
cameraWidth = 640
cameraHeight = 480

face_classifier = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

# calculate the middle screen
midScreenX = int(cameraWidth / 2)
midScreenY = int(cameraHeight / 2)

midScreenWindow = 100

usb = 0

#serial comunication
ser = 0

myself = 0

def face_detector(img):
    # Convert image to grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Clasify face from the gray image
    faces = face_classifier.detectMultiScale(gray, 1.3, 5)
    if faces is ():
        return img, []

    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 255), 2)
        # find the midpoint of the first face in the frame.
        xCentre = int(x + (w / 2))
        yCentre = int(y + (w / 2))
        cv2.circle(img, (xCentre, yCentre), 5, (0, 255, 255), -1)

        localization = [xCentre, yCentre]
        #print(localization)
    return img, localization


class CamView():
    def __init__(self, parent):
        self.parent = parent
        self.window = tk.Toplevel(parent)

        self.lmain2 = tk.Label(self.window)
        self.lmain2.pack()

        self.window.protocol("WM_DELETE_WINDOW", self.close)
        self.show_frame()

    def show_frame(self):
        imgtk = ImageTk.PhotoImage(image=self.parent.img)
        self.lmain2.imgtk = imgtk
        self.lmain2.configure(image=imgtk)

    def close(self):
        self.parent.test_frame = None
        self.window.destroy()





class Main(tk.Frame):


    def __init__(self, parent):

        global usb

        self.lmain = tk.Label(parent)
        self.lmain.pack()



        self.test_frame = None
        frame = tk.Frame.__init__(self,parent)
        a = tk.Label(text='Camera')
        a.pack()
        #a.place(x=0, y=0)
        b = tk.Button(frame, text='open', command=self.load_window)
        b.pack()

        #Properties
        c = tk.Label(text='Properties')
        c.pack()

        # radio buttons to choose the camera
        # If possible, use the variable and update the port automatically
        camPort_var = 1
        radioButtonIn = tk.Radiobutton(text="Internal Webcam",
                                    variable=camPort_var,
                                    value=1,
                                    command=lambda: cameraPort0(radioButtonIn))
        radioButtonEx = tk.Radiobutton(text="External Camera",
                                    variable=camPort_var,
                                    value=2,
                                    command=lambda: cameraPort1(radioButtonEx))

        radioButtonIn.pack()
        radioButtonEx.pack()

        d = tk.Label(text='Serial Port:')
        d.pack()

        #Entry

        #tk.Entry(textvariable=usb_var).pack()
        usb = tk.Entry()
        usb.pack()


        # Button
        #call the function update click when it is clicked
        buttonUpdate = tk.Button(text="Connect", command=self.updateClick)
        buttonUpdate.pack()





        # Set camera resolution. The max resolution is webcam dependent
        # so change it to a resolution that is both supported by your camera
        # and compatible with your monito
        cameraWidth, cameraHeight = 800, 600

        global myself
        myself = self



    # update usb port when the button update is lciked
    def updateClick(self):

        global ser

        print("Ports are Updated " + usb.get())
        ser = serial.Serial(usb.get(), 115200, timeout=.1)
        time.sleep(1)  # give the connection a second to settle
        ser.write(("Hello from Python!").encode())

    def do_stuff(self):
        # Capture frame-by-frame
        _, frame = self.cap.read()
        # mirror the frame
        frame = cv2.flip(frame, 1)

        #function face detector
        image, face = face_detector(frame)

        # cv2.line(image, starting cordinates, ending cordinates, color, thickness)
        # left vertical line
        cv2.line(image, ((midScreenX - midScreenWindow), 0), ((midScreenX - midScreenWindow), cameraHeight),
                 (255, 127, 0), 2)
        # right vertical line
        cv2.line(image, ((midScreenX + midScreenWindow), 0), ((midScreenX + midScreenWindow), cameraHeight),
                 (255, 127, 0), 2)
        # up horizontal line
        cv2.line(image, (0, (midScreenY - midScreenWindow)), (cameraWidth, (midScreenY - midScreenWindow)),
                 (255, 127, 0), 2)
        # down horizontal line
        cv2.line(image, (0, (midScreenY + midScreenWindow)), (cameraWidth, (midScreenY + midScreenWindow)),
                 (255, 127, 0), 2)

        # only if the face is recoginize
        if len(face) == 2:
            midFaceX = face[0]
            midFaceY = face[1]
            # Find out if the X component of the face is to the left of the middle of the screen.
            if (midFaceX < (midScreenX - midScreenWindow)):
                cv2.putText(image, "Move Left", (250, 450), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 2)
                # if(servoPanPosition >= 5):
                # servoPanPosition -= stepSize; #Update the pan position variable to move the servo to the left.
            if (midFaceX > (midScreenX + midScreenWindow)):
                cv2.putText(image, "Move Right", (250, 450), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 2)
            if (midFaceY < (midScreenY - midScreenWindow)):
                cv2.putText(image, "Move Up", (250, 450), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 2)
                var = "2"
                ser.write(var.encode())
                print(var.encode())
            if (midFaceY > (midScreenY + midScreenWindow)):
                cv2.putText(image, "Move Down", (250, 450), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 2)
                var = "8"
                ser.write(var.encode())
                print(var.encode())


                # print(x)
                # print(y)

        cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
        self.img = Image.fromarray(cv2image)
        if self.test_frame != None:
            self.test_frame.show_frame()
        self.lmain.after(10, self.do_stuff)

    def load_window(self):
        if self.test_frame == None:
            self.test_frame = CamView(self)





camerPort = 1  # the camera port default

#update camera port
def cameraPort0(event):
    global myself
    camerPort =0
    print("camera port is " + repr(camerPort))
    # Open Webcam
    # 0 is camera device number, 0 is for internal webcam and 1 will access the first connected usb webcam
    myself.cap = cv2.VideoCapture(camerPort)

    myself.cap.set(cv2.CAP_PROP_FRAME_WIDTH, cameraWidth)
    myself.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, cameraHeight)
    myself.do_stuff()


def cameraPort1(event):
    camerPort = 1
    print("camera port is " + repr(camerPort))
    myself.cap = cv2.VideoCapture(camerPort)

    myself.cap.set(cv2.CAP_PROP_FRAME_WIDTH, cameraWidth)
    myself.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, cameraHeight)
    myself.do_stuff()






root = tk.Tk()
#window title
root.wm_title("Tracker")
#geometry for how big is the window
root.geometry("400x300")
root.bind('<Escape>', lambda e: root.quit())


control = Main(root)
#mainloop is to run the window to be able to constaly display the window
root.mainloop()






