diff --git a/main.py b/main.py
index dd8eec5f682781c19226d61962a3e531e2bec620..02e8383d2717b53875623b16ed9c6db501517a97 100644
--- a/main.py
+++ b/main.py
@@ -23,128 +23,143 @@ def loginAttempt(username: str, password: str) -> StaffUser | ManagerUser | Admi
     else returns None type.
         
     Args:
-        username (str): encrypted username
-        password (str): encrypted password
+        username (str): encrypted username.
+        password (str): encrypted password.
+
+    Raises:
+        ValueError: if db returns invalid permissionLevel.
+    
+    Returns:
+        
+        StaffUser | ManagerUser | AdminUser | None: returns user object or NoneType if login unsucssesfull.
     """
-    del_later = StaffUser()
-    del_later.userName = username
-    del_later.userPass = password
-    return del_later
+    # get permissionLevel and user_id where username and password are match.
+    conditon = json.loads(select_from_tbl_where("tblUsers", f"userName='{username}' AND userPass='{password}'", "permissionLevel"))
+    # based on permissonLevel create the relevant user class object.
+    match conditon["permissionLevel"]:
+        case 0:
+            user = StaffUser()
+        case 1:
+            user = AdminUser()
+        case 2:
+            user = ManagerUser()
+        case _:
+            logging.debug(f"input values {username}, {password} returned non-valid permissionLevel.")
+            raise ValueError()
+    user.login(username, password)
+    return user
 
 def staffUser_options_cli(user:StaffUser) -> None:
-    case = True
-    while case:
-        case = input("Menu options:\n"
+    while True:
+        selection = input("Menu options:\n"
                           "  1. View Listings \n"
                           "  2. Create booking \n"
                           "  3. Logout \n"
                           "  please return a number to select: ")
         # switch case:
-        if case == "1":
-            logging.debug("selection 1, View listings")
-            user.viewFilmListings()
-            # get from cinema the listings and display film data in dict/jason
-            # user.viewFilmListings()
-            # format and display data
-        elif case == "2":
-            logging.debug("selection 2, Create booking")
-            # create booking obj and display attributes for selection
-            # save booking to cinema and db
-            # user.createBooking()
-        elif case == "3":
-            logging.debug("selection 3, logout")
-            user.logout()
-            exit()
-        else:
-            print("Invalid input, please input an integer value corresponding with an option.")
-            case = True
+        match selection:
+            case "1":
+                logging.debug("selection 1, loading View listings")
+                user.viewFilmListings()
+                # get from cinema the listings and display film data in dict/jason
+                # user.viewFilmListings()
+                # format and display data
+            case "2":
+                logging.debug("selection 2, loading Create booking")
+                # create booking obj and display attributes for selection
+                # save booking to cinema and db
+                user.createBooking()
+            case "3":
+                logging.debug("selection 3, loading logout")
+                break
+            case _:
+                print("Invalid input, please input an integer value corresponding with an option.")
+    user.logout()
+    exit()
 
 def managerUser_options_cli(user:ManagerUser) -> None:
-    case = True
-    while case:
-        case = input("Menu options:\n"
+    while True:
+        selection = input("Menu options:\n"
                           "  1. View Listings \n"
                           "  2. Create booking \n"
                           "  3. Logout \n"
                           "  please return a number to select: ")
-        # switch case:
-        if case == "1":
-            logging.debug("selection 1, View listings")
-        elif case == "2":
-            logging.debug("selection 2, Create booking")
-        elif case == "3":
-            logging.debug("selection 3, logout")
-            user.logout()
-            exit()
-        else:
-            print("Invalid input, please input an integer value corresponding with an option.")
-            case = False
+        match selection:
+            case "1":
+                logging.debug("selection 1, loading View listings")
+            case "2":
+                logging.debug("selection 2, loading Create booking")
+            case "3":
+                logging.debug("selection 3, loading logout")
+                break
+            case _:
+                print("Invalid input, please input an integer value corresponding with an option.")
+    user.logout()
+    exit()
 
 def adminUser_options_cli(user:AdminUser) -> None:
-    case = True
-    while case:
-        case = input("Menu options:\n"
+    while True:
+        selection = input("Menu options:\n"
                           "  1. View Listings \n"
                           "  2. Create booking \n"
                           "  3. Logout \n"
                           "  please return a number to select: ")
-        # switch case:
-        if case == "1":
-            logging.debug("selection 1, View listings")
-        elif case == "2":
-            logging.debug("selection 2, Create booking")
-        elif case == "3":
-            logging.debug("selection 3, logout")
-            user.logout()
-            exit()
-        else:
-            print("Invalid input, please input an integer value corresponding with an option.")
-            case = False
+        match selection:
+            case "1":
+                logging.debug("selection 1, loading View listings")
+            case "2":
+                logging.debug("selection 2, loading Create booking")
+            case "3":
+                logging.debug("selection 3, loading logout")
+                break
+            case _:
+                print("Invalid input, please input an integer value corresponding with an option.")
+    user.logout()
+    exit()
+        
 
 def load_cinema(cinemaID) -> Cinema:
-    pass
+    raise NotImplementedError()
 
-def san(string:str) -> str:
+def sanitize(string:str) -> str:
     """
     String sanitization function
     Args:
         string (str): string variable to be sanitized.
     Returns:
-        string but without any escape chars
+        lower case string without any escape chars
     """
-    return string.strip().replace('/', '_').replace('\\', '_')
+    return string.strip().replace('/', '_').replace('\\', '_').lower()
 
 def encrypt(string:str) -> str:
     # add encryption when necessary
     return string
 
-def save():
-    raise NotImplementedError()
-
 def main_cli() -> None:
     print("\n\nSTARTING CINEMA MANAGEMENT SYSTEM.\n\n")
     # test db is connected....
 #    if not getConnection():
 #        logging.critical("Database cannot connect, or dose not exist. \nClosing application.")
 #        exit()
-    user = None
-    while user is None:
-        username = encrypt(san(str(input("To login please enter your credentials.\nUsername: "))))
-        password = encrypt(san(str(input("Password: "))))
+
+    while True:
+        username = encrypt(sanitize(input("To login please enter your credentials.\nUsername: ")))
+        password = encrypt(sanitize(input("Password: ")))
         user = loginAttempt(username=username, password=password)
         if user is None:
             print("Login attempt failed please try again.")
         else:
             break
     logging.info("successful login, loading menu...")
-    user.login()
-
-    if user.permissionLevel == 1:
-        managerUser_options_cli(user)
-    elif user.permissionLevel == 2:
-        adminUser_options_cli(user)
-    else:
-        staffUser_options_cli(user)
+    
+
+    match user.permissionLevel:
+        case 1:
+            managerUser_options_cli(user)
+        case 2:
+            adminUser_options_cli(user)
+        case _:
+            staffUser_options_cli(user)
 
 # following code will only execute if run directly from this file.
 if __name__ == "__main__":
diff --git a/src/constants.py b/src/constants.py
index dc652f59d5acca9b5edf1db9c7341362d6f9ef4e..b8ca0ff898ad48ba62d5b19d2d7d2667cc42ca33 100644
--- a/src/constants.py
+++ b/src/constants.py
@@ -1,5 +1,11 @@
 # all constants are followed by docstrings labeling them, these strings show on hover in most IDEs(vscode and pycharm at least)
 
+# database values:
+DBNAME = "aaaaa"
+DBUSERNAME = ""
+DBPASSWORD = ""
+DBHOSTNAME = ""
+
 # screenObj:
 MAX_SIZE:float = 100.0
 """Maximum screen size in meters"""
diff --git a/src/dbfunc.py b/src/dbfunc.py
index ac61c2b4bb0dde40d7480f83f59de678f7920f9d..e0190f031d0bbc7afe43b7dbfe658b98dc98e2fa 100644
--- a/src/dbfunc.py
+++ b/src/dbfunc.py
@@ -1,20 +1,17 @@
 import logging, json, mysql
+from .constants import DBNAME, DBHOSTNAME, DBUSERNAME, DBPASSWORD
 from mysql.connector import errorcode
 
-# Vars
-hostname = "localhost"
-username = ""
-passwd = ""
+
 
 
 def getConnection(db=""):
     # if specified database
     if db != "":
-        
         try:
-            conn = mysql.connector.connect(host = hostname,
-                user = username,
-                password = passwd,
+            conn = mysql.connector.connect(host = DBHOSTNAME,
+                user = DBUSERNAME,
+                password = DBPASSWORD,
                 database = db)
         except mysql.connector.Error as err:
             if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
@@ -29,9 +26,9 @@ def getConnection(db=""):
     # if database not specified try default from line 5
     else:
         try:
-            conn = mysql.connector.connect(host = hostname,
-                user = username,
-                password = passwd)
+            conn = mysql.connector.connect(host = DBHOSTNAME,
+                user = DBUSERNAME,
+                password = DBPASSWORD)
         except mysql.connector.Error as err:
             if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
                 logging.error("Username or Password is not working")
@@ -41,20 +38,20 @@ def getConnection(db=""):
             logging.error("Connected to server, without database.")
             return conn
         
-def selectFromTbl(table, dbname, *args) -> json:
+def select_from_tbl(table:str, dbname, *args) -> json:
     logging.debug(f"running slect statement with values: tablename='{table}'', dbname='{dbname}'', {args}")
-    conn = getConnection(db=dbname)
+    conn = getConnection(db=DBNAME)
     if conn != None:
         if conn.is_connected():
-            SELECT_STATEMENT = f"SELECT "
+            SELECT_statement = f"SELECT "
             for arg in args:
-                SELECT_STATEMENT.append(f"{arg}, ")
-            SELECT_STATEMENT.removesuffix(", ")
-            SELECT_STATEMENT.append(f" from {table};")
+                SELECT_statement.append(f"{arg}, ")
+            SELECT_statement.removesuffix(", ")
+            SELECT_statement.append(f" from {table};")
             
             dbcursor = conn.cursor()
             dbcursor.execute(f"USE {dbname}")
-            dbcursor.execute(SELECT_STATEMENT)
+            dbcursor.execute(SELECT_statement)
             logging.info("SELECT statement executed successfully.")
             data = dbcursor.fetchall()
             logging.debug(f"dataOut: {data}")
@@ -69,18 +66,39 @@ def selectFromTbl(table, dbname, *args) -> json:
         logging.error("conn returned NoneType")
         raise ConnectionAbortedError()
     
-def selectFromTblWhere(table, dbname, condition, *args) -> json:
-    logging.debug(f"running select statement with values: tablename='{table}'', dbname='{dbname}'', {args}")
-    conn = getConnection(db=dbname)
+def select_from_tbl_where(table:str, condition:str, dbname:str=DBNAME, *args:str) -> json:
+    """_summary_
+    utility function for getting data from database.
+    
+    SQL query format:
+        'SELECT args FROM table WHERE condition;'
+        
+    Args:
+        table (str): table name in database.
+        dbname (str): database name, defult from constants.
+        condition (str): condition used to search table with more detail and smaller retrun.
+
+    Raises:
+        ConnectionAbortedError: if the connection variables are invalid.
+        ConnectionError: if the database could not be connected to.
+
+    Returns:
+        json: json string of returned values.
+    """
+    if len(args) == 0:
+        args = ("*")
+    logging.debug(f"running select statement with values: tablename={table}, dbname={dbname}, condition={condition}, args={args}")
+    conn = getConnection(db=DBNAME)
     if conn == None:
-        logging.error("conn returned NoneType")
+        logging.warning("conn returned NoneType")
         raise ConnectionAbortedError()
     if conn.is_connected():
         SELECT_statement = "SELECT "
         for arg in args:
             SELECT_statement.append(f"{arg}, ")
         SELECT_statement.removesuffix(", ")
-        SELECT_statement.append(f" from {table};")
+        SELECT_statement.append(f" from {table} ")
+        SELECT_statement.append(f"WHERE {condition};")
         
         dbcursor = conn.cursor()
         dbcursor.execute(f"USE {dbname}")
@@ -97,9 +115,10 @@ def selectFromTblWhere(table, dbname, condition, *args) -> json:
         raise ConnectionError()
         
     
-def saveToTbl(table, dbname, jsonData):
+def save_to_Tbl(table, dbname, jsonData):
+    """need to fix"""
     logging.debug(f"running update statment with values: tablename='{table}', dbname='{dbname}', data='{jsonData}'")
-    conn = getConnection(db=dbname)
+    conn = getConnection(db=DBNAME)
     if conn == None:
         logging.error("conn returned NoneType")
         raise ConnectionAbortedError()
diff --git a/src/staffUser.py b/src/staffUser.py
index b77d170b53645905639e6576904b94266aa74eb3..1a80f73fc1944b756cc594c3551120f72e30cec6 100644
--- a/src/staffUser.py
+++ b/src/staffUser.py
@@ -16,33 +16,26 @@ class StaffUser(object):
     def __str__(self):
         return f"{self.__class__.__name__} user object(userID={self.userID}, userName={self.userName}, userPass={self.userPass}, permissionLevel={self.permissionLevel})"
 
-    def login(self, userID) -> None:
+    def login(self, userName, userPassword) -> None:
         """get values for self from db"""
         logging.debug("called login func")
-        jsonData = selectFromTblWhere("tblUsers", "", f"user_id={userID}", "*")
+        jsonData = select_from_tbl_where("tblUsers", f"userName='{userName}' AND userPass='{userPassword}'")
         dictData = json.loads(jsonData)
-        logging.debug(f"loaded data: {dictData}")
-        
-        # update self data with new values.
-        raise NotImplementedError()
-<<<<<<< Updated upstream
-=======
-
-    def login(self):
-        # check if self.userName AND self.userPass in tblUsers, then log
-        logging.debug(f"user {self.userID} logging in.")
-        raise NotImplementedError()
+        logging.debug(f"loaded data: {jsonData}")
+        # this will loop with i as any key from dictData and self.dict that matches, i hope lol.
+        for i in dictData.keys(), self.__dict__.keys():
+            self.i = dictData[i]
 
     def logout(self):
         logging.debug(f"user {self.userID} logging out.")
-        self.save()
->>>>>>> Stashed changes
+        self._save_self_to_db()
+        self.close()
     
     def _save_self_to_db(self) -> None:
         """save self.__dict__ to db."""
         logging.debug("called _save_self_to_db func")
         try:
-            saveToTbl("tblUsers", DBNAME, self.__dict__)
+            save_to_Tbl("tblUsers", DBNAME, self.__dict__)
         except Exception as e:
             logging.error(e.message, e.args)
 
@@ -69,17 +62,20 @@ class StaffUser(object):
         logging.debug("called manageBooking func")
         raise NotImplementedError()
     
-    def cli_view_film_listings(self) -> None:
+    def cli_view_film_listings(self) -> None:       # cant work out how to implement this function in main.py...  would like to remove.
         logging.debug("called cli_viewFilmListing func")
         for i in self.returnFilmListings():
             # will need formating, from json?
             print(f"listing:{i}")
 
-        case = input("Options: 1-exit, 2-move to create booking, 3-logout\n: ")
-        if case == "2":
-            self.createBooking()
-        elif case == "3":
-            self.logout()
+        selection = int(input("Options: 1-exit, 2-move to create booking, 3-logout\n: "))
+        match selection:
+            case 2:
+                self.createBooking()
+            case 3:
+                self.logout()
+            case _:
+                print("input invalid, try again with valid option.")