# Project#8 - Access Granted
# Information - In this project, we're going to create a graphical user interface that requests a username...
# And user password. If the username and user password matches a name and password located in the relative...
# Text file, then the python program will instruct the RPI_no_RPI to activate the relay / deactivate a maglock
# You're going to need to create a text file called "Passwords" in your local folder.
# When you create it, open it and add your name and a password on the first line.
# It should look like this:  Patrick Mitchell 7667
# Add a few more names and passwords on subsequent lines if you want more names to have access
# If you want to create awesome GUIs, I highly recommend this tutorial: https://www.youtube.com/watch?v=YXPyB4XeYLA
from tkinter import *  # Import GUY module
import time            # For delays
import serial          # For microcontroller communication
import playsound       # Why not incorporate some sound bites?  We've done it before, let's do it again.

root = Tk()                 # Needs to be first to great the GUI window
root.title("Security Access")     # Give the GUI a title
root.geometry('270x270')    # 300x300 pixel frame.  Play with these numbers and see what happens!

try:  # Try to establish communication with the RPInoRPI board.  if successful, only the 'try:' will be executed
    MCU = serial.Serial(port='COM10', baudrate=115200, timeout=0.01)  # Timeout = 0.01.  More on this later.
    time.sleep(1)  # Wait 5 seconds.
except:  # If communication with the RPInoRPI could not be established, then perform the following instead:
    print('System Locked - Cannot communicate with MCU.  Close this program, then reconnect to MCU and restart program')
    while True:  # Forever loop.  Close the program and start again.  Check connection to the RPInoRPI
        pass  # Do nothing

def write_read(x):  # This function acts to send data (x) to the RPInoRPI.  Nothing more.
    MCU.write(bytes(x, 'utf-8'))  # Write the value stored in 'x' to the RPInoRPI
    time.sleep(0.2)  # Wait 0.2 seconds/200ms

def buttonclick(number):  # This function takes care of all buttons when pressed.
    # However, there is only one button on this GUI.
    global UsernameEntry  # Set the UsernameEntry window as global variable. Now we can access it across functions.
    global PasswordEntry  # Set the PasswordEntry window as global variable. Now we can access it across functions.
    global FeedbackEntry  # The feedback entry window gives the user information.  Nothing more.
    if number == 1:       # 1 is the button associated with the "LOG IN" button.  If pressed, run the following code:
        Name = UsernameEntry.get()  # Grab the name in the UsernameEntry window and save it to 'Name'
        PW = PasswordEntry.get()    # Grab the password in the PasswordEntry window and save it to 'PW'
        with open("C:/Users/patmxa/Passwords.txt", 'r+') as fp:  # Open the text file.  Use your own link.
            lines = fp.readlines()  # read and store the text file in 'lines'
            SecurityFlag = 0        # This flag will tell the program if access was granted or denied
            for row in lines:       # Check each row in 'lines' - Check every row in Passwords.txt
                if Name in row:     # If the entered user name was in a row in the text file, then do the following:
                    hold = row      # Save the entire row
                    hold = hold.replace('\n', '')  # This is important.  /n means newline, and we need it gone.
                    # Otherwise only the last username/PW in the text file will work
                    print(hold)     # Print the row to the shell to see it (Comment out later as you see fit)
                    hold = hold.replace(Name,'')  # Replace the 'Name' saved above with nothing.  Remove the name
                    print(hold)                   # 'Hold' should now just be the password with a space before it.
                    hold = hold.replace(' ', '')  # Remove the space and replace it with nothing
                    print(hold)                   # See the final sliced product - Just the remaining password
                    if PW == hold:                # If the entered password (PW+ equals the stored password, then...
                        FeedbackEntry.configure(state='normal')  # Make it so that we can make changes to the window value
                        FeedbackEntry.delete(0, END)             # Clear the feedback entry window
                        FeedbackEntry.insert(INSERT,'Access Granted...') # print this to the feedback entry window
                        root.update()   # Update the GUI
                        x = '5'         # x is now '5', which is the deactivation value for the RPI_no_RPI
                        write_read(x)   # Send the RPI_no_RPI the value it needs to deactivate the mag lock
                        time.sleep(10)  # Wait 10 seconds
                        FeedbackEntry.delete(0, END)              # Clear the feedback entry window
                        FeedbackEntry.configure(state='disable')  # Make it so that we can make changes to the window value
                        SecurityFlag = 1  # Set to 1, which will tell the program later on that access was granted
            if SecurityFlag == 0:  # If the flag never changed from 0 to 0, then access was denied.  Do the following:
                x = '4'            # Send the RPI_no_RPI a value that indicates an incorrect set of credentials
                write_read(x)      # Write to RPI_no_RPI
                FeedbackEntry.configure(state='normal')  # Make it so that we can make changes to the window value
                FeedbackEntry.delete(0, END)  # Clear the window
                FeedbackEntry.insert(INSERT,'Access Denied...')  # Print this to the window
                root.update()     # Update the GUI.  Without this, the above FeedbackEntry print won't work
                time.sleep(3)     # Want 3 seconds
                FeedbackEntry.delete(0, END)     # Clear the window
                FeedbackEntry.configure(state='disable')  # Make it so that we can make changes to the window value
    fp.close()  # Close the file



# This is where we set up our GUI
Credentials_Label = Label(root, text='Enter Credentials') # A Labal is basically a title.  This is at the top of the GUI
Credentials_Label.configure(justify='left')         # Set the justification to left.  Can be center or right
Spacer_Label1 = Label(root, text='')                # This label is empty.  We're going to use it as a small spacer
Name_Label = Label(root, text='Enter Name: ')       # Create a label for the  USER NAME entry window
Name_Label.configure(justify='left')                # Left Justify it
UsernameEntry = Entry(root, width=40, borderwidth=5)  # Create a USER NAME entry window
PW_Label = Label(root, text='Enter Password: ')       # Do the same thing for a password entry window label
PW_Label.configure(justify='left')                    # Left Justify
PasswordEntry = Entry(root, width=40, borderwidth=5)  # Create the password entry window
AccessButton = Button(root, text='LOG IN', padx=40, pady=5, command=lambda: buttonclick(1))  # This is for button#1
#  When you press this button, the program opens a text file containing usernames and passwords that have access...
# It reads it, and then determines if the USERNAME and PW entries match any of the access matches in the text file
FeedbackLabel = Label(root, text='System Feedback: ')  # Create a label for the feedback entry window
FeedbackEntry = Entry(root, width=40, borderwidth=5)   # Create the feedback entry window
FeedbackEntry.configure(state='disable')  # Make it so that you can't manually change what is in this window.
UsernameEntry.configure(state='normal')  # Make it so that you can manually change what is in this window.
PasswordEntry.configure(state='normal')  # Make it so that you can manually change what is in this window.


# GRID SETTINGS
# Allocate the area for the operator name and email inputs.
Credentials_Label.grid(row=0,column=0)  # The following four attributes are the email and name entry
Spacer_Label1.grid(row=1,column=0)
Name_Label.grid(row=2,column=0)
UsernameEntry.grid(row=3, column=0, padx=5, pady=5)
PW_Label.grid(row=4,column=0)
PasswordEntry.grid(row=5, column=0, padx=5, pady=5)
AccessButton.grid(row=6, column=0, padx=5, pady=5)
FeedbackLabel.grid(row=7, column=0)
FeedbackEntry.grid(row=8, column=0)
root.mainloop()  # Display everything on the screen and loop until you exit
