/// <summary> /// Runs the specified solve operation asynchronously. /// </summary> /// <typeparam name="TSolveRequest">The type of the solve request for the operation. /// </typeparam> /// <param name="operation">The solve operation to run.</param> /// <returns>Identifier of the started operation.</returns> private Guid _RunAsync <TSolveRequest>( ISolveOperation <TSolveRequest> operation) { this._NotifyAsyncSolveStarting(new AsyncSolveStartingEventArgs(operation.Schedule)); var solveTask = AsyncSolveTask.FromDelegate(tracker => { _ValidateSolverState(); var operationTask = AsyncSolveTask.FromSolveOperation(operation); return(operationTask.Run(tracker)); }); var id = _asyncMgr.RunAsync(solveTask); var info = new AsyncOperationInfo { Id = id, InputParams = operation.InputParams, OperationType = operation.OperationType, Schedule = operation.Schedule, }; _asyncOperations.Add(id, info); _NotifyAsyncSolveStarted(id); return(id); }
/// <summary> /// Method gets orders sent for routing operation, if appropriate operation /// support orders for assigning. /// </summary> /// <param name="info">Operation information.</param> /// <returns>Collection of orders to assign or null if operation /// doesn't support orders to assign.</returns> private ICollection<Order> _GetOrdersToAssign(AsyncOperationInfo info) { Debug.Assert(info != null); ICollection<Order> orders = null; if (info.OperationType == SolveOperationType.BuildRoutes) { BuildRoutesParameters parameters = (BuildRoutesParameters)info.InputParams; orders = parameters.OrdersToAssign; } else if (info.OperationType == SolveOperationType.AssignOrders) { AssignOrdersParams parameters = (AssignOrdersParams)info.InputParams; orders = parameters.OrdersToAssign; } else { // Do nothing: other operation doesn't support OrdersToAssign. } return orders; }
/// <summary> /// Method shows that Order was assigned to that Route /// in message window. /// </summary> /// <param name="schedule">Schedule.</param> /// <param name="info">Operation info.</param> protected void _ShowSuccessfullyAssignedOrders(Schedule schedule, AsyncOperationInfo info) { var assignOrdersDetails = _GetSuccessfullyAssignedOrdersDetails(schedule, info); // Add success details only in case of more than 1 orders assigned, // otherwise head message is good enough. if (assignOrdersDetails.Count > 1) { App.Current.Messenger.AddInfo( _FormatSuccessSolveCompletedMsg(schedule, info), assignOrdersDetails); } else { assignOrdersDetails.Clear(); App.Current.Messenger.AddInfo( _FormatSuccessSolveCompletedMsg(schedule, info), assignOrdersDetails); } }
/// <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); }
/// <summary> /// Success solve completed message string is various for each command /// </summary> /// <returns></returns> protected abstract string _FormatSuccessSolveCompletedMsg(Schedule schedule, AsyncOperationInfo info);
/// <summary> /// Method saves schedule /// </summary> private void _ProcessSaveSchedule(Schedule schedule, AsyncOperationInfo info) { // set unassigned orders if (null != schedule.UnassignedOrders) schedule.UnassignedOrders.Dispose(); schedule.UnassignedOrders = App.Current.Project.Orders.SearchUnassignedOrders(schedule, true); // save results App.Current.Project.Save(); }
/// <summary> /// Method gets status message: unassign operation completed, /// for multiple unassign operation. /// </summary> /// <param name="schedule">Schedule where operation proceeded.</param> /// <param name="info">Operation information.</param> /// <returns>Message.</returns> public static string GetMultipleUnassignOperationCompletedMessage( Schedule schedule, AsyncOperationInfo info) { Debug.Assert(schedule != null); Debug.Assert(info != null); string result = string.Empty; var orders = ((UnassignOrdersParams)info.InputParams).OrdersToUnassign; int unassignedOrdersCount = orders.Count; if (unassignedOrdersCount == 1) { // Create message for only one unassigned order. Order order = orders.First(); if (order != null) { result = string.Format( (string)App.Current.FindResource(ORDER_UNASSIGNED_FROM_SCHEDULES), order.Name, schedule.Name); } } else { // Create message for all unassigned orders. result = string.Format( (string)App.Current.FindResource(ORDERS_UNASSIGNED_FROM_SCHEDULES), unassignedOrdersCount, schedule.Name); } return result; }
/// <summary> /// Gets message string about solve completed successfully. /// </summary> /// <param name="schedule">Edited schedule.</param> /// <param name="info">Operation info.</param> /// <returns>Success solve string.</returns> protected override string _FormatSuccessSolveCompletedMsg(Schedule schedule, ESRI.ArcLogistics.Routing.AsyncOperationInfo info) { return(RoutingMessagesHelper.GetAssignOperationCompletedMessage(info)); }
/// <summary> /// Method formats success message. /// </summary> /// <param name="schedule">Edited schedule.</param> /// <param name="info">Operation info.</param> /// <returns>Info string.</returns> protected override string _FormatSuccessSolveCompletedMsg(Schedule schedule, AsyncOperationInfo info) { string message = string.Empty; // If oreders was assigned to any route. if (info.OperationType == SolveOperationType.AssignOrders) message = RoutingMessagesHelper.GetAssignOperationCompletedMessage(info); // If orders was unassigned. else if (info.OperationType == SolveOperationType.UnassignOrders) message = RoutingMessagesHelper.GetUnassignOperationCompletedMessage(info); else { // Not supported yet. Debug.Assert(false); } return message; }
/// <summary> /// Gets asynchronous operation info. /// </summary> /// <param name="operationId">Operation id.</param> /// <param name="info">AsyncOperationInfo object.</param> /// <returns> /// true if info object is set, false if operation with specified id /// was not found. /// </returns> public bool GetAsyncOperationInfo(Guid operationId, out AsyncOperationInfo info) { return(_asyncOperations.TryGetValue(operationId, out info)); }
/// <summary> /// Method gets route name for assigned order. /// </summary> /// <param name="info">Operation info.</param> /// <param name="order">Assigned order.</param> /// <returns>Route name or empty string, in case order is unassigned.</returns> private static string _GetRouteNameForAssignedOrder( AsyncOperationInfo info, Order order) { Debug.Assert(info != null); Debug.Assert(order != null); var inputParameters = (AssignOrdersParams)info.InputParams; ICollection<Route> targetRoutes = inputParameters.TargetRoutes; // Search for stop associated with order, which was assigned to route. var assignedStops = from route in targetRoutes where route.Stops != null from stop in route.Stops where (stop.AssociatedObject == order) select stop; string routeName = string.Empty; if (assignedStops.Any()) { Stop stop = assignedStops.First(); routeName = stop.Route.Name; } return routeName; }
/// <summary> /// Method gets name of route which contains assigned orders. /// </summary> /// <param name="info">Operation information.</param> /// <returns>Route name.</returns> private static string _GetAssignedRouteName(AsyncOperationInfo info) { Debug.Assert(info != null); var inputParameters = (AssignOrdersParams)info.InputParams; ICollection<Route> targetRoutes = inputParameters.TargetRoutes; string routeName = null; if (targetRoutes.Count == 1) { // In most cases only one route is targeted. routeName = string.Format( (string)App.Current.FindResource(OPTION_WITH_QUOTES), targetRoutes.First().Name); } else { // Orders assigned to Best Route. routeName = (string)App.Current.FindResource(BEST_ROUTES_RESOURCE_NAME); } return routeName; }
/// <summary> /// Method gets status message: unassign operation completed. /// </summary> /// <param name="info">Operation information.</param> /// <returns>Message.</returns> public static string GetUnassignOperationCompletedMessage(AsyncOperationInfo info) { Debug.Assert(info != null); string result = string.Empty; var orders = ((UnassignOrdersParams)info.InputParams).OrdersToUnassign; int unassignedOrdersCount = orders.Count; string unassignedOrdersName = (string)App.Current.FindResource(UNASSIGNED_ORDERS_RESOURCE_NAME); if (unassignedOrdersCount == 1) { // Create message for only one unassigned order. Order order = orders.First(); if (order != null) { result = string.Format( (string)App.Current.FindResource(ORDER_MOVED), order.Name, unassignedOrdersName); } } else { // Create message for all unassigned orders. result = string.Format( (string)App.Current.FindResource(ALL_ORDERS_MOVED), unassignedOrdersCount, unassignedOrdersName); } return result; }
/// <summary> /// Method gets details messages about successfully assigned orders during /// routing operation. Details message are expanded by route names. /// </summary> /// <param name="schedule">Schedule.</param> /// <param name="info">Operation info.</param> /// <returns>Collection of message details.</returns> private ICollection<MessageDetail> _GetSuccessfullyAssignedOrdersDetails( Schedule schedule, AsyncOperationInfo info) { var routedOrdersDetails = new Collection<MessageDetail>(); ICollection<Order> ordersToAssign = _GetOrdersToAssign(info); if (ordersToAssign == null) return routedOrdersDetails; // Find all pairs Route & Order. var detailsPairs = new List<KeyValuePair<Route, Order>>(); foreach (Order order in ordersToAssign) foreach (Route route in schedule.Routes) foreach (Stop stop in route.Stops) if (stop.AssociatedObject is Order && ((Order)stop.AssociatedObject).Equals(order)) { var pair = new KeyValuePair<Route, Order>( route, order); detailsPairs.Add(pair); } string formatString = (string)App.Current.FindResource(ORDERS_SUCCESSFULLY_ASSIGNED); // Add messages expanded by Routes. foreach (Route route in schedule.Routes) foreach (KeyValuePair<Route, Order> pair in detailsPairs) { if (pair.Key.Name == route.Name) { DataObject[] parameters = new DataObject[] { pair.Value, pair.Key }; MessageDetail detail = new MessageDetail(MessageType.Information, formatString, parameters); routedOrdersDetails.Add(detail); } } return routedOrdersDetails; }
/// <summary> /// Creates success unassigned complete message /// </summary> /// <param name="schedule"></param> /// <param name="info"></param> /// <returns></returns> private string _FormatSuccessSolveCompletedMsg( Schedule schedule, AsyncOperationInfo info) { return RoutingMessagesHelper.GetMultipleUnassignOperationCompletedMessage(schedule, info); }
/// <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> /// 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> /// Gets message about Solve completed successfully. /// </summary> /// <param name="schedule">Edited schedule.</param> /// <param name="info">Operation info.</param> /// <returns>Message string.</returns> protected override string _FormatSuccessSolveCompletedMsg(Schedule schedule, AsyncOperationInfo info) { return RoutingMessagesHelper.GetUnassignOperationCompletedMessage(info); }
/// <summary> /// Method gets status message: assign operation completed. /// </summary> /// <param name="info">Operation information.</param> /// <returns>Message.</returns> public static string GetAssignOperationCompletedMessage(AsyncOperationInfo info) { Debug.Assert(info != null); var inputParameters = (AssignOrdersParams)info.InputParams; ICollection<Order> ordersToAssign = inputParameters.OrdersToAssign; int numberOfReassignedOrders = _GetNumberOfReassignedOrders(inputParameters); int numberOfOrdersToAssign = ordersToAssign.Count; string routeName = _GetAssignedRouteName(info); string message = string.Empty; if (numberOfReassignedOrders == 0) { // No orders moved. if (numberOfOrdersToAssign == 1) { // Add message for one not moved order. Order order = ordersToAssign.First(); if (order != null) { message = string.Format((string)App.Current.FindResource(ORDER_FAILED_TO_MOVE), order.Name, routeName); } } else { // Add message for all not moved orders. message = string.Format((string)App.Current.FindResource(ALL_ORDERS_FAILED_TO_MOVE), numberOfOrdersToAssign, routeName); } } else if (numberOfReassignedOrders == 1 && numberOfReassignedOrders == numberOfOrdersToAssign) { // Add message for one moved order. Order order = ordersToAssign.First(); if (order != null) { // We can determine exact route name for one order, // if it was assigned to any Best Route. if (routeName == (string)App.Current.FindResource(BEST_ROUTES_RESOURCE_NAME)) { routeName = _GetRouteNameForAssignedOrder(info, order); Debug.Assert(!string.IsNullOrEmpty(routeName)); routeName = string.Format((string)App.Current.FindResource(OPTION_WITH_QUOTES), routeName); } // Create final message. message = string.Format((string)App.Current.FindResource(ORDER_MOVED), order.Name, routeName); } } else if (numberOfReassignedOrders > 1 && numberOfReassignedOrders == numberOfOrdersToAssign) { // Add message for All moved orders. message = string.Format((string)App.Current.FindResource(ALL_ORDERS_MOVED), numberOfReassignedOrders, routeName); } else { // Add message for some of orders moved. message = string.Format((string)App.Current.FindResource(SOME_ORDERS_MOVED), numberOfReassignedOrders, numberOfOrdersToAssign, routeName); } return message; }