/// <summary>
        /// Creates collection of message detail when solve operation failed
        /// </summary>
        /// <param name="schedule"></param>
        /// <param name="info"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        private ICollection <MessageDetail> _GetErrorFailedDetails(AsyncOperationInfo info, SolveResult result)
        {
            Debug.Assert(info != null);
            Debug.Assert(result != null);

            // Create details.
            ICollection <MessageDetail> details = null;

            if (0 < result.Violations.Count)
            {
                details = ViolationMessageBuilder.GetViolationDetails(info.Schedule, info, result.Violations);
            }
            else
            {
                // Create details from solver error message.
                details = new Collection <MessageDetail>();
                details.Add(new MessageDetail(MessageType.Error, RoutingCmdHelpers.FormatSolverErrorMsg(result)));
            }

            return(details);
        }
        /// <summary>
        /// Method shows result messages for operation with Parial Success.
        /// </summary>
        /// <param name="violations">List of operations occured.</param>
        /// <param name="schedule">Schedule.</param>
        /// <param name="info">Operation info.</param>
        private void _ShowPartialSuccessOperationResults(IList <Violation> violations,
                                                         Schedule schedule, AsyncOperationInfo info)
        {
            // Add violations results.
            ICollection <MessageDetail> details =
                ViolationMessageBuilder.GetViolationDetails(schedule,
                                                            info, violations);

            // For Build Routes or Assign to Best Route operations
            // after violations list add successfully moved orders results.
            if (info.OperationType == SolveOperationType.BuildRoutes)
            {
                var routedOrdersDetails =
                    _GetSuccessfullyAssignedOrdersDetails(schedule, info);

                foreach (var detail in routedOrdersDetails)
                {
                    details.Add(detail);
                }
            }
            else if (info.OperationType == SolveOperationType.AssignOrders)
            {
                AssignOrdersParams parameters = (AssignOrdersParams)info.InputParams;

                // Is this operation is targeted to Best Route.
                if (parameters.TargetRoutes.Count > 1)
                {
                    var assignedOrdersDetails =
                        _GetSuccessfullyAssignedOrdersDetails(schedule, info);

                    foreach (var detail in assignedOrdersDetails)
                    {
                        details.Add(detail);
                    }
                }
            }

            App.Current.Messenger.AddMessage(
                _FormatSuccessSolveCompletedMsg(schedule, info), details);
        }
        /// <summary>
        /// Saves new schedule if it's build correctly or show error message.
        /// </summary>
        /// <param name="res">Solve result.</param>
        /// <param name="schedule">Schedule.</param>
        /// <param name="info">Operation info.</param>
        protected void _SaveSchedule(SolveResult res, Schedule schedule, AsyncOperationInfo info)
        {
            // if solver returns "failed"
            if (res.IsFailed)
            {
                // show result message(s)
                string message = string.Format(
                    (string)App.Current.FindResource(ROUTING_OPERATION_FAILED),
                    schedule.PlannedDate.Value.ToShortDateString());
                ICollection <MessageDetail> details = null;
                if (0 < res.Violations.Count)
                {
                    details = ViolationMessageBuilder.GetViolationDetails(schedule, info, res.Violations);
                }
                // Create details from solver error message.
                else
                {
                    details = new Collection <MessageDetail>();
                    var errorMessage = RoutingCmdHelpers.FormatSolverErrorMsg(res);

                    // If we have error message - add message detail.
                    if (errorMessage.Length != 0)
                    {
                        details.Add(new MessageDetail(MessageType.Error, errorMessage));
                    }
                }

                App.Current.Messenger.AddError(message, details);
            }
            else
            {
                // set unassigned orders
                if (null != schedule.UnassignedOrders)
                {
                    schedule.UnassignedOrders.Dispose();
                }

                // save route results
                Project project = App.Current.Project;
                project.Save();

                schedule.UnassignedOrders = project.Orders.SearchUnassignedOrders(schedule, true);

                // In case operation is Build Routes we should create "Original Schedule" if doesn't exist yet.
                // Schedule must be current.
                if (info.OperationType == SolveOperationType.BuildRoutes)
                {
                    if (schedule.Type == ScheduleType.BuildRoutesSnapshot)
                    {
                        // update current schedule (according to CR133526)
                        _UpdateSchedule(ScheduleType.Current, schedule,
                                        (string)App.Current.FindResource("CurrentScheduleName"));

                        // update build routes snapshot name
                        schedule.Name = _FormatBuildRoutesSnapshotName();
                    }
                    else
                    {
                        // update build routes snapshot
                        _UpdateSchedule(ScheduleType.BuildRoutesSnapshot, schedule, _FormatBuildRoutesSnapshotName());
                    }

                    // save changes
                    project.Save();
                }

                // Show result message(s).
                if (0 < res.Violations.Count)
                {
                    _ShowPartialSuccessOperationResults(res.Violations, schedule, info);
                }
                else
                {
                    // If operation type is Assign To Routes
                    // show that Order was assigned to that Route
                    if (info.OperationType.Equals(SolveOperationType.AssignOrders))
                    {
                        _ShowSuccessfullyAssignedOrders(schedule, info);
                    }
                    else
                    {
                        App.Current.Messenger.AddInfo(
                            _FormatSuccessSolveCompletedMsg(schedule, info));
                    }
                }
            }

            OptimizeAndEditPage page = (OptimizeAndEditPage)((MainWindow)App.Current.MainWindow).GetPage(PagePaths.SchedulePagePath);

            if (null != page)
            {
                page.OnScheduleChanged(schedule);
            }
        }