public static PlanElement Create(DecisionRow row, int orderNo, DateTime start, DateTime end) { var element = new PlanElement { PlaceName = row.Candidate.PlaceName, PlaceId = row.Candidate.PlaceId, FormattedAddress = row.Candidate.FormattedAddress, Lat = row.Candidate.Location.lat, Lng = row.Candidate.Location.lng, OrderNo = orderNo, Rating = row.Candidate.Rating, Price = row.Candidate.Price, Popularity = row.Candidate.Popularity, ScorePosition = row.ScorePosition, NormalizedScore = row.NormalizedScore, Start = start, End = end }; element.PlanElementTypes = new List <PlanElementyTypeEntity>(row.Candidate.ElementTypes.Count); foreach (var e in row.Candidate.ElementTypes) { element.PlanElementTypes.Add(new PlanElementyTypeEntity(e)); } element.OpeningHours = new List <PlanElementOpeningHourEntity>(row.Candidate.OpeningHours.Count); foreach (var e in row.Candidate.OpeningHours) { element.OpeningHours.Add(new PlanElementOpeningHourEntity(e)); } return(element); }
public async Task <IList <PlanElement> > GenerateAsync(DecisionArray decisionArray, Plan plan) { var elements = new List <PlanElement>(); var optimizedElementsOrder = await _optimizePlanElementsOrder.Optimize(decisionArray, plan, plan.Assumptions.AssumedNumberOfElement); //travel salesman problem optimization var optimizedPosition = 1; foreach (var optimizedIter in optimizedElementsOrder) { decisionArray.DecisionRows[optimizedIter].OptimizedPosition = optimizedPosition; ++optimizedPosition; } //Sort by optimized position decisionArray.DecisionRows = decisionArray.DecisionRows.OrderBy(x => x.OptimizedPosition).ToList(); var iterParams = new PlanElementIteratorParams(plan.StartLocation, plan.PlanForm.StartDateTime, plan.Assumptions); while (DateTime.Compare(iterParams.CurrentDateTime, plan.PlanForm.EndDateTime) <= 0 || iterParams.OrderNo >= decisionArray.DecisionRows.Count) { try { PlanElement planElement = null; //EATING if (iterParams.IsTimeForMeal()) { var elementEndTime = iterParams.CreateEndDateTime(plan.Assumptions.EatingDuration); var candidate = await _planElementEatingProvider.GenerateAsync(decisionArray, plan, iterParams.WhichMeal, iterParams); iterParams.CheckNextMeal(); planElement = new PlanElement(candidate.PlaceName, candidate.PlaceId, candidate.FormattedAddress, iterParams.CurrentDateTime, elementEndTime, candidate.Location.lat, candidate.Location.lng, iterParams.OrderNo, candidate.Rating, candidate.Price, candidate.Popularity, PlanElementType.Eating); } //SLEEPING else if (iterParams.IsTimeForSleep()) { iterParams.IsSleep = true; var elementEndTime = iterParams.CreateEndDateTime(plan.Assumptions.SleepDuration); if (plan.PlanForm.HasAccomodationBooked) { planElement = new PlanElement(plan.PlanAccomodation.PlaceName, plan.PlanAccomodation.PlaceId, plan.PlanAccomodation.FormattedAddress, iterParams.CurrentDateTime, elementEndTime, plan.PlanAccomodation.Lat, plan.PlanAccomodation.Lng, iterParams.OrderNo, plan.PlanAccomodation.Rating, null, null, PlanElementType.Sleeping); } else { planElement = new PlanElement(plan.PlanForm.PlaceName, plan.PlanForm.PlaceId, String.Empty, iterParams.CurrentDateTime, elementEndTime, plan.Latitude, plan.Longitude, iterParams.OrderNo, plan.Rating, null, null, PlanElementType.Sleeping); } } //OTHER PLAN ELEMENTS else { var foundRow = false; var elementEndTime = iterParams.CreateEndDateTime(plan.Assumptions.PlanElementDuration); while (!foundRow) { if (iterParams.LeftRows.Any(x => x.Candidate.IsOpen(iterParams.CurrentDateTime))) //first check lefted row which was temporary closed { var leftedRow = iterParams.LeftRows.First(x => x.Candidate.IsOpen(iterParams.CurrentDateTime)); if (!leftedRow.Candidate.IsOpen(elementEndTime)) //check close date { elementEndTime = leftedRow.Candidate.GetCloseDateTime(iterParams.CurrentDateTime, elementEndTime); } planElement = PlanElement.Create(leftedRow, iterParams.OrderNo, iterParams.CurrentDateTime, elementEndTime); iterParams.LeftRows.Remove(leftedRow); foundRow = true; } else if (decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex].Candidate.IsOpen(iterParams.CurrentDateTime)) //decision row is open { if (!decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex].Candidate.IsOpen(elementEndTime)) //check close date { elementEndTime = decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex].Candidate.GetCloseDateTime(iterParams.CurrentDateTime, elementEndTime); } planElement = PlanElement.Create(decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex], iterParams.OrderNo, iterParams.CurrentDateTime, elementEndTime); foundRow = true; iterParams.CurrentDecisionRowIndex += 1; } else //decision row is closed { iterParams.LeftRows.Add(decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex]); iterParams.CurrentDecisionRowIndex += 1; } } } if (iterParams.CurrentDecisionRowIndex == decisionArray.DecisionRows.Count()) { throw new UserFriendlyException($"Skończyły się dostępni kandydaci"); } if (planElement == null) { continue; } iterParams.NextLocation = Location.Create(planElement.Lat, planElement.Lng); //DIRECTIONS var directionsApiInput = _googleDirectionsInputFactory.Create(iterParams.CurrentLocation, iterParams.NextLocation, iterParams.travelMode, iterParams.CurrentDateTime); var directionsApiResult = await _googleDirectionsApiClient.GetAsync(directionsApiInput); if (directionsApiResult.IsOk) { if (directionsApiResult.routes.First().legs.Any()) { var route = directionsApiResult.routes.First().legs.First(); //only 1 leg if no waypoints var planRoute = new PlanRoute(route.distance.value, route.duration.value, iterParams.travelMode); foreach (var step in route.steps) //steps of route { planRoute.Steps.Add(new PlanRouteStep(step.distance.value, step.duration.value, step.start_location.lat, step.start_location.lng, step.end_location.lat, step.end_location.lng, InterpreteEnums.InterpreteTravelMode(step.travel_mode), step.html_instructions, step.maneuver)); } //update plan element times planElement.UpdateDateTimeWithRouteDuration(planRoute.TimeDuration); planElement.EndingRoute = planRoute; } } elements.Add(planElement); //add to plan list iterParams.SetCurrentLocation(planElement.Lat, planElement.Lng); // update currentLocation in iterParams iterParams.CurrentDateTime = planElement.End; //update current time in iterParams ++iterParams.OrderNo; //increase iter) iterParams.ClearIfEndOfCurrentDay(); } catch (Exception e) { var error = e.InnerException; break; } } return(elements); }