Example #1
0
        /// <summary>
        /// The Method to do what the User decieded
        /// </summary>
        /// <param name="data">The Data payload passed by the User</param>
        /// <param name="activityResultID">The Result ID Passed by the User to indicate which step to proceed to.</param>
        /// <returns></returns>
        public override async Task <CompletionResult> Complete(string data, Guid?activityResultID)
        {
            if (!activityResultID.HasValue)
            {
                activityResultID = SaveResultID;
            }

            var task = PmnTask.GetActiveTaskForRequestActivity(_entity.ID, ID, db);

            if (activityResultID == SaveResultID)
            {
                await task.LogAsModifiedAsync(_workflow.Identity, db);

                await db.SaveChangesAsync();

                return(new CompletionResult
                {
                    ResultID = SaveResultID
                });
            }
            else if (activityResultID == BulkEditResultID)
            {
                await task.LogAsModifiedAsync(_workflow.Identity, db);

                await db.SaveChangesAsync();

                return(new CompletionResult
                {
                    ResultID = BulkEditResultID
                });
            }
            else if (activityResultID == RemoveDatamartsResultID)
            {
                Guid[] guids    = data.Split(',').Select(s => Guid.Parse(s)).ToArray();
                var    routings = await db.RequestDataMarts.Where(dm => guids.Contains(dm.ID)).ToArrayAsync();

                foreach (var routing in routings)
                {
                    routing.Status = DTO.Enums.RoutingStatus.Canceled;
                }

                await task.LogAsModifiedAsync(_workflow.Identity, db);

                await db.SaveChangesAsync();

                var originalStatus = _entity.Status;
                await db.SaveChangesAsync();

                await db.Entry(_entity).ReloadAsync();

                if (originalStatus != DTO.Enums.RequestStatuses.Complete && _entity.Status == DTO.Enums.RequestStatuses.Complete)
                {
                    await NotifyRequestStatusChanged(originalStatus, DTO.Enums.RequestStatuses.Complete);
                }

                return(new CompletionResult
                {
                    ResultID = RemoveDatamartsResultID
                });
            }
            else if (activityResultID == CompleteRoutingResultID)
            {
                var uiResponse = Newtonsoft.Json.JsonConvert.DeserializeObject <WebResponseModel>(data);

                var routing = await db.RequestDataMarts.Include("Request").SingleOrDefaultAsync(dm => dm.ID == uiResponse.RequestDM && dm.RequestID == _entity.ID);

                var response = await db.Responses.SingleOrDefaultAsync(res => res.ID == uiResponse.Response && res.RequestDataMartID == uiResponse.RequestDM);

                response.ResponseTime    = DateTime.UtcNow;
                response.RespondedByID   = _workflow.Identity.ID;
                response.ResponseMessage = uiResponse.Comment;
                var originalRequestStatus = routing.Request.Status;
                var originalStatus        = routing.Status;


                //We should only update the routing status if it is not already complete or modified.
                if (originalStatus != DTO.Enums.RoutingStatus.Completed && originalStatus != DTO.Enums.RoutingStatus.ResultsModified)
                {
                    routing.Status = DTO.Enums.RoutingStatus.Completed;
                }

                if (routing.Status == DTO.Enums.RoutingStatus.Completed || routing.Status == DTO.Enums.RoutingStatus.ResultsModified)
                {
                    try
                    {
                        var trackingTableProcessor = new DistributedRegressionTrackingTableProcessor(db);
                        await trackingTableProcessor.Process(response);
                    }
                    catch (Exception ex)
                    {
                        //should not block if fails
                    }
                }

                await db.SaveChangesAsync();

                await db.Entry <RequestDataMart>(routing).ReloadAsync();

                await db.Entry <Request>(_entity).ReloadAsync();

                var completeStatuses = new[] {
                    Lpp.Dns.DTO.Enums.RoutingStatus.Completed,
                    Lpp.Dns.DTO.Enums.RoutingStatus.ResultsModified,
                    Lpp.Dns.DTO.Enums.RoutingStatus.RequestRejected,
                    Lpp.Dns.DTO.Enums.RoutingStatus.ResponseRejectedBeforeUpload,
                    Lpp.Dns.DTO.Enums.RoutingStatus.ResponseRejectedAfterUpload,
                    Lpp.Dns.DTO.Enums.RoutingStatus.AwaitingResponseApproval
                };



                var incompletedRoutings = await db.RequestDataMarts.Where(dm => dm.RequestID == _entity.ID &&
                                                                          dm.RoutingType != DTO.Enums.RoutingType.AnalysisCenter &&
                                                                          !completeStatuses.Contains(dm.Status)).CountAsync();

                if (incompletedRoutings == 0)
                {
                    try
                    {
                        var routingProcessor = new DistributedRegressionRoutingProcessor(db, _workflow.Identity.ID);
                        await routingProcessor.Process(routing);

                        return(new CompletionResult
                        {
                            ResultID = CompleteRoutingResultToAC
                        });
                    }
                    catch (Exception ex)
                    {
                        throw;
                    }
                }
                else
                {
                    await task.LogAsModifiedAsync(_workflow.Identity, db);

                    await db.SaveChangesAsync();

                    return(new CompletionResult
                    {
                        ResultID = CompleteRoutingResultID
                    });
                }
            }
            else if (activityResultID == TerminateResultID)
            {
                db.Requests.Remove(_entity);

                if (task != null)
                {
                    db.Actions.Remove(task);
                }

                await db.SaveChangesAsync();

                return(new CompletionResult
                {
                    ResultID = TerminateResultID
                });
            }
            else
            {
                throw new NotSupportedException(CommonMessages.ActivityResultNotSupported);
            }
        }
        /// <summary>
        /// The Method to do what the User decieded
        /// </summary>
        /// <param name="data">The Data payload passed by the User</param>
        /// <param name="activityResultID">The Result ID Passed by the User to indicate which step to proceed to.</param>
        /// <returns></returns>
        public override async Task <CompletionResult> Complete(string data, Guid?activityResultID)
        {
            if (!activityResultID.HasValue)
            {
                activityResultID = SaveResultID;
            }

            var task = PmnTask.GetActiveTaskForRequestActivity(_entity.ID, ID, db);

            if (activityResultID == SaveResultID)
            {
                await task.LogAsModifiedAsync(_workflow.Identity, db);

                await db.SaveChangesAsync();

                return(new CompletionResult
                {
                    ResultID = SaveResultID
                });
            }
            else if (activityResultID == RedistributeResultID)
            {
                if (!await db.HasPermissions <Project>(_workflow.Identity, _entity.ProjectID, Lpp.Dns.DTO.Security.PermissionIdentifiers.Project.ResubmitRequests))
                {
                    throw new System.Security.SecurityException(CommonMessages.RequirePermissionToResubmitRequest, Lpp.Dns.DTO.Security.PermissionIdentifiers.Project.ResubmitRequests.GetType());
                }

                ResubmitRoutingsModel resubmitModel = Newtonsoft.Json.JsonConvert.DeserializeObject <ResubmitRoutingsModel>(data);

                var datamarts = await(
                    from dm in db.RequestDataMarts.Include(dm => dm.Responses)
                    where dm.RequestID == _entity.ID &&
                    dm.Responses.Any(r => resubmitModel.Responses.Contains(r.ID) || (r.ResponseGroupID.HasValue && resubmitModel.Responses.Contains(r.ResponseGroupID.Value)))
                    select dm
                    ).ToArrayAsync();


                //for the last completed routing from the AC
                //look for the file_list.csv document, if does not exist use all files
                //if file_list.csv exists, only use the documents it specifies

                List <Guid> documentRevisionSetIDs = new List <Guid>();

                var previousInputRequestDocuments = await(from d in db.Documents.AsNoTracking()
                                                          join reqDoc in (from rd in db.RequestDocuments
                                                                          where rd.DocumentType == DTO.Enums.RequestDocumentType.Output &&
                                                                          rd.Response.RequestDataMart.RoutingType == DTO.Enums.RoutingType.AnalysisCenter &&
                                                                          rd.Response.Count == rd.Response.RequestDataMart.Responses.Where(rsp => rsp.RespondedByID.HasValue).Max(rsp => rsp.Count) &&
                                                                          rd.Response.RequestDataMart.RequestID == _entity.ID
                                                                          select rd) on d.RevisionSetID equals reqDoc.RevisionSetID
                                                          where d.ID == db.Documents.Where(dd => dd.RevisionSetID == d.RevisionSetID).OrderByDescending(dd => dd.MajorVersion).ThenByDescending(dd => dd.MinorVersion).ThenByDescending(dd => dd.BuildVersion).ThenByDescending(dd => dd.RevisionVersion).Select(dd => dd.ID).FirstOrDefault()
                                                          select d).ToArrayAsync();

                // look for the first document with kind == "DistributedRegression.FileList".
                Document fileListDocument = previousInputRequestDocuments.Where(d => !string.IsNullOrEmpty(d.Kind) && string.Equals("DistributedRegression.FileList", d.Kind, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                if (fileListDocument != null)
                {
                    //only include the files indicated in the manifest
                    byte[] fileListBytes = fileListDocument.GetData(db);
                    using (var ms = new System.IO.MemoryStream(fileListBytes))
                        using (var reader = new System.IO.StreamReader(ms))
                        {
                            //read the header line
                            reader.ReadLine();

                            string line, filename;
                            bool   includeInDistribution = false;
                            while (!reader.EndOfStream)
                            {
                                line = reader.ReadLine();
                                string[] split = line.Split(',');
                                if (split.Length > 0)
                                {
                                    filename = split[0].Trim();
                                    if (split.Length > 1)
                                    {
                                        includeInDistribution = string.Equals(split[1].Trim(), "1");
                                    }
                                    else
                                    {
                                        includeInDistribution = false;
                                    }

                                    if (includeInDistribution == false)
                                    {
                                        continue;
                                    }

                                    if (!string.IsNullOrEmpty(filename))
                                    {
                                        Guid?revisionSetID = previousInputRequestDocuments.Where(d => string.Equals(d.FileName, filename, StringComparison.OrdinalIgnoreCase)).Select(d => d.RevisionSetID).FirstOrDefault();
                                        if (revisionSetID.HasValue)
                                        {
                                            documentRevisionSetIDs.Add(revisionSetID.Value);
                                        }
                                    }
                                }
                            }

                            reader.Close();
                        }
                }
                else
                {
                    //include all documents
                    documentRevisionSetIDs.AddRange(previousInputRequestDocuments.Select(d => d.RevisionSetID.Value).Distinct());
                }


                DateTime reSubmittedOn = DateTime.UtcNow;
                foreach (var dm in datamarts)
                {
                    var response = dm.AddResponse(_workflow.Identity.ID);
                    response.SubmittedOn   = reSubmittedOn;
                    response.SubmitMessage = resubmitModel.ResubmissionMessage;

                    dm.Status = DTO.Enums.RoutingStatus.Resubmitted;

                    foreach (var revisionSetID in documentRevisionSetIDs)
                    {
                        db.RequestDocuments.Add(new RequestDocument {
                            ResponseID = response.ID, RevisionSetID = revisionSetID, DocumentType = DTO.Enums.RequestDocumentType.Input
                        });
                    }
                }

                await SetRequestStatus(DTO.Enums.RequestStatuses.Submitted);

                await task.LogAsModifiedAsync(_workflow.Identity, db);

                await db.SaveChangesAsync();

                return(new CompletionResult
                {
                    ResultID = RedistributeResultID
                });
            }
            else if (activityResultID == BulkEditResultID)
            {
                await task.LogAsModifiedAsync(_workflow.Identity, db);

                await db.SaveChangesAsync();

                return(new CompletionResult
                {
                    ResultID = BulkEditResultID
                });
            }
            else if (activityResultID == AddDatamartsResultID)
            {
                DTO.QueryComposer.QueryComposerRequestDTO requestDTO = Newtonsoft.Json.JsonConvert.DeserializeObject <DTO.QueryComposer.QueryComposerRequestDTO>(_entity.Query);
                var modularTerm = requestDTO.Where.Criteria.SelectMany(c => c.Terms.Where(t => t.Type == DistributedRegressionConfiguration.ModularProgramTermID)).FirstOrDefault();
                var termValues  = Newtonsoft.Json.JsonConvert.DeserializeObject <ModularProgramTermValues>(modularTerm.Values["Values"].ToString());

                string[] datamartIDs = data.Split(',');

                var allTasks = await db.ActionReferences.Where(tr => tr.ItemID == _entity.ID &&
                                                               tr.Type == DTO.Enums.TaskItemTypes.Request &&
                                                               tr.Task.Type == DTO.Enums.TaskTypes.Task
                                                               )
                               .Select(tr => tr.Task.ID).ToArrayAsync();

                var attachments = await(from doc in db.Documents.AsNoTracking()
                                        join x in (
                                            db.Documents.Where(dd => allTasks.Contains(dd.ItemID))
                                            .GroupBy(k => k.RevisionSetID)
                                            .Select(k => k.OrderByDescending(d => d.MajorVersion).ThenByDescending(d => d.MinorVersion).ThenByDescending(d => d.BuildVersion).ThenByDescending(d => d.RevisionVersion).Select(y => y.ID).Distinct().FirstOrDefault())
                                            ) on doc.ID equals x
                                        where allTasks.Contains(doc.ItemID) && doc.Kind == "Attachment.Input"
                                        orderby doc.ItemID descending, doc.RevisionSetID descending, doc.CreatedOn descending
                                        select doc).ToArrayAsync();

                foreach (var guid in datamartIDs)
                {
                    Guid dmGuid = new Guid(guid);

                    var dm = RequestDataMart.Create(_entity.ID, dmGuid, _workflow.Identity.ID);
                    dm.Status      = DTO.Enums.RoutingStatus.Submitted;
                    dm.DueDate     = _entity.DueDate;
                    dm.Priority    = _entity.Priority;
                    dm.RoutingType = DTO.Enums.RoutingType.DataPartner;
                    _entity.DataMarts.Add(dm);

                    Response rsp = dm.Responses.OrderByDescending(r => r.Count).FirstOrDefault();
                    //add the request document associations
                    foreach (var revisionSetID in termValues.Documents.Select(d => d.RevisionSetID))
                    {
                        db.RequestDocuments.Add(new RequestDocument {
                            DocumentType = DTO.Enums.RequestDocumentType.Input, ResponseID = rsp.ID, RevisionSetID = revisionSetID
                        });
                    }

                    foreach (var attachment in attachments)
                    {
                        db.RequestDocuments.Add(new RequestDocument {
                            RevisionSetID = attachment.RevisionSetID.Value, ResponseID = rsp.ID, DocumentType = DTO.Enums.RequestDocumentType.AttachmentInput
                        });
                    }
                }

                await task.LogAsModifiedAsync(_workflow.Identity, db);

                await db.SaveChangesAsync();

                return(new CompletionResult
                {
                    ResultID = AddDatamartsResultID
                });
            }
            else if (activityResultID == RemoveDatamartsResultID)
            {
                Guid[] guids    = data.Split(',').Select(s => Guid.Parse(s)).ToArray();
                var    routings = await db.RequestDataMarts.Where(dm => guids.Contains(dm.ID)).ToArrayAsync();

                foreach (var routing in routings)
                {
                    routing.Status = DTO.Enums.RoutingStatus.Canceled;
                }

                await task.LogAsModifiedAsync(_workflow.Identity, db);

                await db.SaveChangesAsync();

                var originalStatus = _entity.Status;
                await db.SaveChangesAsync();

                await db.Entry(_entity).ReloadAsync();

                if (originalStatus != DTO.Enums.RequestStatuses.Complete && _entity.Status == DTO.Enums.RequestStatuses.Complete)
                {
                    await NotifyRequestStatusChanged(originalStatus, DTO.Enums.RequestStatuses.Complete);
                }

                return(new CompletionResult
                {
                    ResultID = RemoveDatamartsResultID
                });
            }
            else if (activityResultID == CompleteRoutingResultID)
            {
                var uiResponse = Newtonsoft.Json.JsonConvert.DeserializeObject <WebResponseModel>(data);

                var routing = await db.RequestDataMarts.Include("Request").SingleOrDefaultAsync(dm => dm.ID == uiResponse.RequestDM && dm.RequestID == _entity.ID);

                var response = await db.Responses.SingleOrDefaultAsync(res => res.ID == uiResponse.Response && res.RequestDataMartID == uiResponse.RequestDM);

                response.ResponseTime    = DateTime.UtcNow;
                response.RespondedByID   = _workflow.Identity.ID;
                response.ResponseMessage = uiResponse.Comment;
                var originalRequestStatus = routing.Request.Status;
                var originalStatus        = routing.Status;


                //We should only update the routing status if it is not already complete or modified.
                if (originalStatus != DTO.Enums.RoutingStatus.Completed && originalStatus != DTO.Enums.RoutingStatus.ResultsModified)
                {
                    routing.Status = DTO.Enums.RoutingStatus.Completed;
                }

                if (routing.Status == DTO.Enums.RoutingStatus.Completed || routing.Status == DTO.Enums.RoutingStatus.ResultsModified)
                {
                    try
                    {
                        var trackingTableProcessor = new DistributedRegressionTrackingTableProcessor(db);
                        await trackingTableProcessor.Process(response);
                    }
                    catch (Exception ex)
                    {
                        //should not block if fails
                    }
                }

                await db.SaveChangesAsync();

                await db.Entry <RequestDataMart>(routing).ReloadAsync();

                await db.Entry <Request>(_entity).ReloadAsync();

                var completeStatuses = new[] {
                    Lpp.Dns.DTO.Enums.RoutingStatus.Completed,
                    Lpp.Dns.DTO.Enums.RoutingStatus.ResultsModified,
                    Lpp.Dns.DTO.Enums.RoutingStatus.RequestRejected,
                    Lpp.Dns.DTO.Enums.RoutingStatus.ResponseRejectedBeforeUpload,
                    Lpp.Dns.DTO.Enums.RoutingStatus.ResponseRejectedAfterUpload,
                    Lpp.Dns.DTO.Enums.RoutingStatus.AwaitingResponseApproval
                };



                var incompletedRoutings = await db.RequestDataMarts.Where(dm => dm.RequestID == _entity.ID &&
                                                                          dm.RoutingType != DTO.Enums.RoutingType.AnalysisCenter &&
                                                                          !completeStatuses.Contains(dm.Status)).CountAsync();

                if (incompletedRoutings == 0)
                {
                    try
                    {
                        var routingProcessor = new DistributedRegressionRoutingProcessor(db, _workflow.Identity.ID);
                        await routingProcessor.Process(routing);

                        return(new CompletionResult
                        {
                            ResultID = CompleteRoutingResultToAC
                        });
                    }
                    catch (Exception ex)
                    {
                        throw;
                    }
                }
                else
                {
                    await task.LogAsModifiedAsync(_workflow.Identity, db);

                    await db.SaveChangesAsync();

                    return(new CompletionResult
                    {
                        ResultID = CompleteRoutingResultID
                    });
                }
            }
            else if (activityResultID == TerminateResultID)
            {
                db.Requests.Remove(_entity);

                if (task != null)
                {
                    db.Actions.Remove(task);
                }

                await db.SaveChangesAsync();

                return(new CompletionResult
                {
                    ResultID = TerminateResultID
                });
            }
            else
            {
                throw new NotSupportedException(CommonMessages.ActivityResultNotSupported);
            }
        }
        public async Task <DMCRoutingStatusProcessorResult> UpdateStatusAsync(dmc.Criteria.SetRequestStatusData data)
        {
            PermissionDefinition permission = data.Status == dmc.Enums.DMCRoutingStatus.Hold ? PermissionIdentifiers.DataMartInProject.HoldRequest : (data.Status == dmc.Enums.DMCRoutingStatus.RequestRejected ? PermissionIdentifiers.DataMartInProject.RejectRequest : PermissionIdentifiers.DataMartInProject.UploadResults);

            bool hasPermission = await CheckPermission(data.RequestID, data.DataMartID, permission, Identity.ID);

            if (hasPermission == false)
            {
                string message = data.Status == dmc.Enums.DMCRoutingStatus.Hold ? "You do not have permission to change the status of this request to Hold" :
                                 (data.Status == dmc.Enums.DMCRoutingStatus.RequestRejected ? "You do not have permission to change the status of this request to Rejected" : "You do not have permission to upload results.");

                return(new DMCRoutingStatusProcessorResult(HttpStatusCode.Forbidden, message));
            }

            //var currentResponse = await DataContext.Responses.Include(rsp => rsp.RequestDataMart).Where(rsp => rsp.RequestDataMart.RequestID == data.RequestID && rsp.RequestDataMart.DataMartID == data.DataMartID && rsp.Count == rsp.RequestDataMart.Responses.Select(x => x.Count).Max()).FirstOrDefaultAsync();
            var details = await(
                from rsp in DataContext.Responses
                join rdm in DataContext.RequestDataMarts on rsp.RequestDataMartID equals rdm.ID
                join r in DataContext.Requests on rdm.RequestID equals r.ID
                where rdm.RequestID == data.RequestID && rdm.DataMartID == data.DataMartID &&
                rsp.Count == rdm.Responses.Select(x => x.Count).Max()
                select new
            {
                Response = rsp,
                Routing  = rdm,
                Request  = r
            }
                ).FirstOrDefaultAsync();


            if (details == null)
            {
                return(new DMCRoutingStatusProcessorResult(HttpStatusCode.NotFound, "Unable to determine the routing information based on the specified RequestID and DataMart ID."));
            }

            var currentResponse = details.Response;
            var routing         = details.Routing;
            var request         = details.Request;

            var orginalRequestStatus = request.Status;
            var originalStatus       = routing.Status;

            hasPermission = await CheckPermission(data.RequestID, data.DataMartID, PermissionIdentifiers.DataMartInProject.SkipResponseApproval, request.CreatedByID);

            if (originalStatus == DTO.Enums.RoutingStatus.Hold && data.Status == dmc.Enums.DMCRoutingStatus.Submitted && currentResponse.Count > 1)
            {
                routing.Status = DTO.Enums.RoutingStatus.Resubmitted;
            }
            else if (originalStatus == DTO.Enums.RoutingStatus.Completed || originalStatus == DTO.Enums.RoutingStatus.ResultsModified)
            {
                routing.Status = hasPermission ? DTO.Enums.RoutingStatus.ResultsModified : DTO.Enums.RoutingStatus.AwaitingResponseApproval;
            }
            else
            {
                routing.Status = (Lpp.Dns.DTO.Enums.RoutingStatus)((int)data.Status);

                if (routing.Status == DTO.Enums.RoutingStatus.AwaitingResponseApproval)
                {
                    if (hasPermission)
                    {
                        routing.Status = DTO.Enums.RoutingStatus.Completed;
                    }
                }
            }

            //updating the UpdatedOn property of the routing so that logs will get processed and will allow for status change notification to go out if further uploads are done while status is ResultsModified.
            routing.UpdatedOn  = DateTime.UtcNow;
            routing.Properties = data.Properties == null ? null :
                                 "<P>" + string.Join("",
                                                     from p in data.Properties
                                                     where !string.IsNullOrEmpty(p.Name)
                                                     select string.Format("<V Key=\"{0}\">{1}</V>", p.Name, p.Value)) +
                                 "</P>";

            currentResponse.ResponseMessage = data.Message;

            //only set the response time and ID if the response is completed
            var completeStatuses = new[] {
                Lpp.Dns.DTO.Enums.RoutingStatus.Completed,
                Lpp.Dns.DTO.Enums.RoutingStatus.ResultsModified,
                Lpp.Dns.DTO.Enums.RoutingStatus.RequestRejected,
                Lpp.Dns.DTO.Enums.RoutingStatus.ResponseRejectedBeforeUpload,
                Lpp.Dns.DTO.Enums.RoutingStatus.ResponseRejectedAfterUpload,
                Lpp.Dns.DTO.Enums.RoutingStatus.AwaitingResponseApproval,
                Lpp.Dns.DTO.Enums.RoutingStatus.Hold
            };

            bool routingIsComplete = completeStatuses.Contains(routing.Status);

            if (routingIsComplete)
            {
                currentResponse.ResponseTime  = DateTime.UtcNow;
                currentResponse.RespondedByID = Identity.ID;
            }

            if ((routing.Status == DTO.Enums.RoutingStatus.Completed || routing.Status == DTO.Enums.RoutingStatus.ResultsModified) && routing.Request.WorkflowID.HasValue)
            {
                try
                {
                    var trackingTableProcessor = new DistributedRegressionTrackingTableProcessor(DataContext);
                    await trackingTableProcessor.Process(currentResponse);
                }
                catch (Exception ex)
                {
                    //should not block if fails
                    Logger.Error(string.Format("Error processing tracking table for response ID: {0}\r\n{1}", currentResponse.ID, Lpp.Utilities.ExceptionHelpers.UnwindException(ex, true)), ex.InnerException ?? ex);
                }
            }

            await DataContext.SaveChangesAsync();

            await DataContext.Entry(request).ReloadAsync();

            if (!data.Message.IsEmpty())
            {
                var log = await DataContext.LogsRoutingStatusChange.OrderByDescending(x => x.TimeStamp).FirstOrDefaultAsync(x => x.ResponseID == currentResponse.ID);

                log.Description += $" {data.Message}";


                await DataContext.SaveChangesAsync();
            }

            if (request.WorkflowID.HasValue && request.WorkflowID.Value == VerticalDistributedRegressionWorkflowID && (routing.Status == DTO.Enums.RoutingStatus.Completed || routing.Status == DTO.Enums.RoutingStatus.ResultsModified))
            {
                try
                {
                    await DataContext.Entry(routing).Reference(r => r.Request).LoadAsync();

                    var routingProcessor = new VerticalDistributedRegressionRoutingProcessor(DataContext, Identity.ID);
                    await routingProcessor.Process(routing);
                }
                catch (Exception ex)
                {
                    Logger.Error(string.Format("Error processing distributed regression route transistion for request ID: {0}\r\n{1}", routing.RequestID, Lpp.Utilities.ExceptionHelpers.UnwindException(ex, true)), ex.InnerException ?? ex);
                    throw;
                }
            }
            else if (routingIsComplete && request.Status == DTO.Enums.RequestStatuses.Complete && request.WorkflowID.HasValue)
            {
                if (request.WorkflowID.Value == HorizontalDistributedRegressionWorkflowID && (routing.Status == DTO.Enums.RoutingStatus.Completed || routing.Status == DTO.Enums.RoutingStatus.ResultsModified))
                {
                    try
                    {
                        await DataContext.Entry(routing).Reference(r => r.Request).LoadAsync();

                        var routingProcessor = new DistributedRegressionRoutingProcessor(DataContext, Identity.ID);
                        await routingProcessor.Process(routing);
                    }
                    catch (Exception ex)
                    {
                        Logger.Error(string.Format("Error processing distributed regression route transistion for request ID: {0}\r\n{1}", routing.RequestID, Lpp.Utilities.ExceptionHelpers.UnwindException(ex, true)), ex.InnerException ?? ex);
                        throw;
                    }
                }

                //reload the request to get the current request status.
                await DataContext.Entry(request).ReloadAsync();

                if (request.Status == DTO.Enums.RequestStatuses.Complete)
                {
                    //send the request status complete notification
                    var      requestStatusLogger = new Dns.Data.RequestLogConfiguration();
                    string[] emailText           = await requestStatusLogger.GenerateRequestStatusChangedEmailContent(DataContext, request.ID, Identity.ID, orginalRequestStatus, request.Status);

                    var logItems = requestStatusLogger.GenerateRequestStatusEvents(DataContext, Identity, false, orginalRequestStatus, request.Status, request.ID, emailText[1], emailText[0], "Request Status Changed");

                    await DataContext.SaveChangesAsync();

                    await Task.Run(() =>
                    {
                        List <Utilities.Logging.Notification> notifications = new List <Utilities.Logging.Notification>();

                        foreach (Lpp.Dns.Data.Audit.RequestStatusChangedLog logitem in logItems)
                        {
                            var items = requestStatusLogger.CreateNotifications(logitem, DataContext, true);
                            if (items != null && items.Any())
                            {
                                notifications.AddRange(items);
                            }
                        }

                        if (notifications.Any())
                        {
                            requestStatusLogger.SendNotification(notifications);
                        }
                    });
                }
            }

            return(new DMCRoutingStatusProcessorResult());
        }
        public async Task CreateLogForNonDistributedRegressionRequest()
        {
            Guid requestID = Guid.Parse("C8702FA2-C9AC-4CC4-82BE-A84D0118904C");
            var  Identity  = new Lpp.Utilities.Security.ApiIdentity(Guid.Parse("9F400001-FAD6-4E84-8933-A2380151C648"), "jmalenfant", null);

            using (var DataContext = new Dns.Data.DataContext())
            {
                var requestQuery = DataContext.Secure <Request>(Identity).Where(r => r.ID == requestID);


                var builder = new Lpp.Dns.Data.DistributedRegressionTracking.EnhancedEventLogBuilder();

                builder.RequestStatusChangeEvents = async() => {
                    var evts = await(from l in DataContext.LogsRequestStatusChanged
                                     let dtTimestamp = DbFunctions.CreateDateTime(l.TimeStamp.Year, l.TimeStamp.Month, l.TimeStamp.Day, l.TimeStamp.Hour, l.TimeStamp.Minute, l.TimeStamp.Second)
                                                       where requestQuery.Any() &&
                                                       l.RequestID == requestID
                                                       select new
                    {
                        l.TimeStamp,
                        //treat the step as the lowest response count where the response is submitted after the status change log item timestamp or zero
                        Step = DataContext.Responses.Where(rsp => rsp.RequestDataMart.RequestID == l.RequestID && rsp.SubmittedOn >= dtTimestamp).Select(rsp => (int?)rsp.Count).Min() ?? 0,
                        l.Description
                    }).ToArrayAsync();

                    return(evts.Select(l => new EnhancedEventLogItemDTO
                    {
                        Timestamp = l.TimeStamp.DateTime,
                        Source = string.Empty,
                        Step = l.Step,
                        Description = l.Description
                    }));
                };

                builder.RoutingStatusChangeEvents = async() =>
                {
                    var evts = await(from l in DataContext.LogsRoutingStatusChange
                                     let dtTimestamp = DbFunctions.CreateDateTime(l.TimeStamp.Year, l.TimeStamp.Month, l.TimeStamp.Day, l.TimeStamp.Hour, l.TimeStamp.Minute, l.TimeStamp.Second)
                                                       where requestQuery.Any() &&
                                                       l.RequestDataMart.RequestID == requestID
                                                       select new
                    {
                        Timestamp   = l.TimeStamp,
                        Source      = l.RequestDataMart.DataMart.Name,
                        Description = l.Description,
                        //treat the step as the maximum response count where the response is submitted before the status change log item timestamp or zero
                        Step = l.RequestDataMart.Responses.Where(rsp => rsp.SubmittedOn <= dtTimestamp).Select(rsp => (int?)rsp.Count).Max() ?? 0
                    }).ToArrayAsync();

                    return(evts.Select(l => new EnhancedEventLogItemDTO
                    {
                        Timestamp = l.Timestamp.DateTime,
                        Source = l.Source,
                        Step = l.Step,
                        Description = l.Description
                    }));
                };

                builder.DocumentUploadEvents = async() =>
                {
                    var lastDocumentUpload = await(from rsp in DataContext.Responses
                                                   let lastDoc = (from rd in DataContext.RequestDocuments
                                                                  join doc in DataContext.Documents on rd.RevisionSetID equals doc.RevisionSetID
                                                                  where rd.ResponseID == rsp.ID &&
                                                                  rd.DocumentType == RequestDocumentType.Output
                                                                  orderby doc.CreatedOn descending
                                                                  select doc).FirstOrDefault()
                                                                 where rsp.RequestDataMart.RequestID == requestID &&
                                                                 requestQuery.Any() &&
                                                                 rsp.ResponseTime != null &&
                                                                 lastDoc != null
                                                                 select new
                    {
                        Iteration         = rsp.Count,
                        DataMart          = rsp.RequestDataMart.DataMart.Name,
                        DocumentCreatedOn = lastDoc.CreatedOn
                    }).ToArrayAsync();


                    return(lastDocumentUpload.Select(l => new EnhancedEventLogItemDTO
                    {
                        Timestamp = l.DocumentCreatedOn,
                        Source = l.DataMart,
                        Step = l.Iteration,
                        Description = "Files finished uploading"
                    }));
                };



                ////parse latest AC tracking table
                ////parse any DP tracking tables that are iteration a head of AC

                var dataPartners = await DataContext.RequestDataMarts.Where(rdm => rdm.RequestID == requestID).Select(rdm => new { rdm.DataMart.Name, Identifier = (rdm.DataMart.DataPartnerIdentifier ?? rdm.DataMart.Acronym), rdm.RoutingType }).ToDictionaryAsync(k => k.Identifier);

                builder.TrackingTableEvents = async() =>
                {
                    //get the ID of the latest Analysis tracking document
                    var latestACTrackingDocumentID = await(from rd in DataContext.RequestDocuments
                                                           join doc in DataContext.Documents on rd.RevisionSetID equals doc.RevisionSetID
                                                           where rd.Response.RequestDataMart.RequestID == requestID &&
                                                           requestQuery.Any() &&
                                                           rd.Response.RequestDataMart.RoutingType == RoutingType.AnalysisCenter &&
                                                           rd.Response.Count == rd.Response.RequestDataMart.Responses.Max(rsp => rsp.Count) &&
                                                           doc.Kind == "DistributedRegression.TrackingTable"
                                                           orderby doc.MajorVersion, doc.MinorVersion, doc.BuildVersion, doc.RevisionVersion descending
                                                           select doc.ID).FirstOrDefaultAsync();

                    if (latestACTrackingDocumentID == default(Guid))
                    {
                        return(Array.Empty <EnhancedEventLogItemDTO>());
                    }

                    IEnumerable <Data.DistributedRegressionTracking.TrackingTableItem> trackingTableItems;
                    using (var db = new DataContext())
                        using (var stream = new Data.Documents.DocumentStream(db, latestACTrackingDocumentID))
                        {
                            trackingTableItems = await DistributedRegressionTrackingTableProcessor.Read(stream);
                        }

                    List <EnhancedEventLogItemDTO> logItems = new List <EnhancedEventLogItemDTO>(trackingTableItems.Count());

                    int lastIteration = trackingTableItems.Max(t => t.Iteration);

                    foreach (var partnerEntries in trackingTableItems.GroupBy(k => k.DataPartnerCode))
                    {
                        var dataPartnerName = dataPartners[TranslatePartnerIdentifier(partnerEntries.Key)].Name;

                        foreach (var iteration in partnerEntries.GroupBy(k => k.Iteration))
                        {
                            if (iteration.Key == 0 || iteration.Key == lastIteration)
                            {
                                //read from the last start time
                                logItems.Add(new EnhancedEventLogItemDTO
                                {
                                    Step        = iteration.Key,
                                    Description = "SAS program execution begin",
                                    Source      = dataPartnerName,
                                    Timestamp   = iteration.Max(l => l.Start)
                                });
                            }
                            else
                            {
                                //if DP read the latest start
                                //if AC read the 2nd last start time

                                //TODO: talk to Qoua - I don't think this is valid logic/rule
                                logItems.Add(new EnhancedEventLogItemDTO
                                {
                                    Step        = iteration.Key,
                                    Description = "SAS program execution begin",
                                    Source      = dataPartnerName,
                                    Timestamp   = iteration.Max(l => l.Start)
                                });
                            }
                            //read the last end time
                            logItems.Add(new EnhancedEventLogItemDTO
                            {
                                Step        = iteration.Key,
                                Description = "SAS program execution complete, output files written.",
                                Source      = dataPartnerName,
                                Timestamp   = iteration.Max(l => l.End)
                            });
                        }
                        ;
                    }
                    ;


                    return(logItems);
                };

                //builder.AdapterLoggedEvents = async () => {

                //    List<EnhancedEventLogItemDTO> logItems = new List<EnhancedEventLogItemDTO>();

                //    //get the adapter event logs, will need to know the response iteration, and the datamart name

                //    var adapterLogs = await (from rd in DataContext.RequestDocuments
                //                             let doc = (from d in DataContext.Documents where d.RevisionSetID == rd.RevisionSetID && d.Kind == "DistributedRegression.AdapterEventLog" select d).DefaultIfEmpty()
                //                             where rd.DocumentType == RequestDocumentType.Output
                //                             && rd.Response.RequestDataMart.RequestID == requestID
                //                             && requestQuery.Any()
                //                             && doc.Any()
                //                             select
                //                             new
                //                             {
                //                                 ResponseID = rd.ResponseID,
                //                                 ResponseIteration = rd.Response.Count,
                //                                 DataMart = rd.Response.RequestDataMart.DataMart.Name,
                //                                 DocumentID = doc.OrderByDescending(d => d.MajorVersion).ThenByDescending(d => d.MinorVersion).ThenByDescending(d => d.BuildVersion).ThenByDescending(d => d.RevisionVersion).Select(d => d.ID).FirstOrDefault()
                //                             }).ToArrayAsync();

                //    foreach (var log in adapterLogs)
                //    {
                //        //get the log content
                //        using (var db = new DataContext())
                //        using (var streamReader = new StreamReader(new Data.Documents.DocumentStream(db, log.DocumentID)))
                //        using (var reader = new Newtonsoft.Json.JsonTextReader(streamReader))
                //        {
                //            var serializer = new Newtonsoft.Json.JsonSerializer();
                //            var adapterEvents = serializer.Deserialize<IEnumerable<EventLogItem>>(reader)
                //            .Select(al => new EnhancedEventLogItemDTO
                //            {
                //                Step = log.ResponseIteration,
                //                Source = log.DataMart,
                //                Description = al.Description,
                //                Timestamp = al.Timestamp
                //            }).ToArray();

                //            if (adapterEvents.Length > 0)
                //            {
                //                logItems.AddRange(adapterEvents);
                //            }
                //        }
                //    }

                //    return logItems;
                //};

                var eventLog = await builder.GetItems();

                StringBuilder sb = new StringBuilder();
                foreach (var item in eventLog)
                {
                    //Console.WriteLine("{0}\t{1:o}\t{2}\t{3}", item.Step, item.Timestamp, item.Source, item.Description);
                    //Logger.InfoFormat("{0}\t{1:o}\t{2}\t{3}\r\n", item.Step, item.Timestamp, item.Source, item.Description);
                    sb.AppendLine(string.Format("{0}\t{1:o}\t{2}\t{3}", item.Step, item.Timestamp, item.Source, item.Description));
                }

                Logger.Info("Event Log:\n" + sb.ToString());
            }
        }