} // End of AddAttendanceStateBLL

        /// <summary>
        /// Business logic for processing AttendanceState description change.
        /// </summary>
        /// <param name="taskType"></param>
        /// <returns></returns>
        internal object ModifyAttendanceStateBLL(AttendanceStateDTO attendanceState)
        {
            // Create a new APIException object to store possible exceptions as checks are performed.
            APIException exceptionList = new APIException();

            // Due to the number of checks, this approach is more appropriate
            Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>()
            {
                { "Specified StateID does not exist", !_context.AttendanceStates.Any(x => x.StateID == attendanceState.StateID) },
                { "description parameter cannot be empty", attendanceState.Description == null || attendanceState.Description.Trim() == string.Empty },
                { "description must be unique", !string.IsNullOrEmpty(attendanceState.Description) && _context.AttendanceStates.Any(x => x.Description.ToLower() == attendanceState.Description.Trim().ToLower() && x.StateID != attendanceState.StateID) }
            };

            foreach (KeyValuePair <string, bool> kvp in exceptionTests)
            {
                if (kvp.Value)
                {
                    exceptionList.AddExMessage(kvp.Key);
                }
            }

            if (!exceptionList.HasExceptions)
            {
                // Capitalise the first letter of the first word of the description
                string dbDescription = $"{attendanceState.Description.Trim().Substring(0, 1).ToUpper()}{attendanceState.Description.Trim().Substring(1)?.ToLower()}";
                attendanceState.Description = dbDescription;
                return(attendanceState);
            }
            else
            {
                return(exceptionList);
            }
        } // End of ModifyAttendanceStateBLL
        /// <summary>
        /// Business logic for processing AttendanceState record addition
        /// </summary>
        /// <param name="description"></param>
        /// <returns></returns>
        internal object AddAttendanceStateBLL(string description)
        {
            // Create a new APIException object to store possible exceptions as checks are performed.
            APIException exceptionList = new APIException();

            Dictionary <string, bool> exceptionTests = new Dictionary <string, bool>()
            {
                { "description parameter cannot be empty", description == null || description.Trim() == string.Empty },
                { "description must be unique", !string.IsNullOrEmpty(description) && _context.AttendanceStates.Any(x => x.Description.ToLower() == description.Trim().ToLower()) }
            };

            foreach (KeyValuePair <string, bool> kvp in exceptionTests)
            {
                if (kvp.Value)
                {
                    exceptionList.AddExMessage(kvp.Key);
                }
            }

            if (!exceptionList.HasExceptions)
            {
                // Capitalise the first letter of the first word of the description
                string dbDescription = $"{description.Trim().Substring(0, 1).ToUpper()}{description.Trim().Substring(1)?.ToLower()}";

                AttendanceStateDTO newDbObject = new AttendanceStateDTO {
                    Description = dbDescription
                };

                return(newDbObject);
            }
            else
            {
                return(exceptionList);
            }
        } // End of AddAttendanceStateBLL
    public async Task <ActionResult> ModifyAttendanceState([FromBody] AttendanceStateDTO attendanceState)
    {
        if (AttendanceStateExists(attendanceState.StateID))
        {
            // Call BLL AttendanceState Modify method with all the parameters
            object BLLResponse = new AttendanceStateBLL(_context).ModifyAttendanceStateBLL(attendanceState: attendanceState);

            if (BLLResponse.GetType().BaseType == typeof(Exception))
            {
                // Create log entries for Debug log
                ((APIException)BLLResponse).Exceptions.ForEach(ex => Logger.Msg <AttendanceStatesController>((Exception)ex, Serilog.Events.LogEventLevel.Debug));

                // Return response from API
                return(BadRequest(new { errors = ((APIException)BLLResponse).Exceptions.Select(x => x.Message).ToArray() }));
            }
            else
            {
                try
                {
                    AttendanceStateDTO modAttendanceState = (AttendanceStateDTO)BLLResponse;

                    // Find the existing record based on ID
                    AttendanceState currentRecord = _context.AttendanceStates.Where(x => x.StateID == modAttendanceState.StateID).First();

                    // Modify the record
                    currentRecord.Description = modAttendanceState.Description;

                    // Save changes
                    await _context.SaveChangesAsync();

                    Logger.Msg <AttendanceStatesController>($"[{User.FindFirstValue("email")}] [MODIFY] StateID: {currentRecord.StateID} successful", Serilog.Events.LogEventLevel.Information);

                    // Return modified record as a DTO
                    AttendanceStateDTO response = new AttendanceStateDTO(currentRecord);
                    return(Ok(response));
                }
                catch (Exception ex)
                {
                    // Local log entry. Database reconciliation issues are more serious so reported as Error
                    Logger.Msg <AttendanceStatesController>($"[MODIFY] Database sync error {ex.Message}", Serilog.Events.LogEventLevel.Error);

                    // Return response to client
                    return(StatusCode(500, new { errors = "Database update failed. Contact the administrator to resolve this issue." }));
                }
            }
        }
        else
        {
            return(NotFound());
        }
    } // End of ModifyAttendanceState
    public async Task <ActionResult> AddAttendanceState(string description)
    {
        // Call BLL Attendance Add method with all the parameters
        object BLLResponse = new AttendanceStateBLL(_context).AddAttendanceStateBLL(description: description);

        // Get the base class for the response
        // Ref: https://docs.microsoft.com/en-us/dotnet/api/system.type.basetype?view=netcore-3.1
        if (BLLResponse.GetType().BaseType == typeof(Exception))
        {
            // Create log entries for Debug log
            ((APIException)BLLResponse).Exceptions.ForEach(ex => Logger.Msg <AttendanceStatesController>((Exception)ex, Serilog.Events.LogEventLevel.Debug));

            // Return response from API
            return(BadRequest(new { errors = ((APIException)BLLResponse).Exceptions.Select(x => x.Message).ToArray() }));
        }
        else
        {
            try
            {
                AttendanceState newAttendanceState = new AttendanceState {
                    Description = ((AttendanceStateDTO)BLLResponse).Description
                };

                // Create the record
                _context.AttendanceStates.Add(newAttendanceState);
                await _context.SaveChangesAsync();

                Logger.Msg <AttendanceStatesController>($"[{User.FindFirstValue("email")}] [ADD] AttendanceState '{description}' successful", Serilog.Events.LogEventLevel.Information);

                // Convert back to DTO and return to user
                AttendanceStateDTO response = new AttendanceStateDTO(newAttendanceState);
                return(Ok(response));
            }
            catch (Exception ex)
            {
                // Local log entry. Database reconciliation issues are more serious so reported as Error
                Logger.Msg <AttendanceStatesController>($"[ADD] Database sync error {ex.Message}", Serilog.Events.LogEventLevel.Error);

                // Return response to client
                return(StatusCode(500, new { errors = "Database update failed. Contact the administrator to resolve this issue." }));
            }
        }
    } // End of AddAttendanceState