예제 #1
0
        public async Task <PlanElementCandidate> GenerateAsync(DecisionArray decisionArray, Plan plan, int whichMeal, PlanElementIteratorParams iterParams)
        {
            var test = true;
            //choose type based on preferences
            var type                  = (plan.PlanForm.FoodPreference == FoodPreference.OnlyRestaurant || (plan.PlanForm.FoodPreference == FoodPreference.Mixed && whichMeal == 2)) ? GooglePlaceTypeCategory.Restaurant : GooglePlaceTypeCategory.Food;
            var candidates            = new List <PlanElementCandidate>();
            var decisionRows          = new List <DecisionRow>();
            var googleNearbyFoodInput = _googlePlaceNearbySearchInputFactory.Create(iterParams.CurrentLocation, type);
            var nearbyFoodResults     = await _googlePlaceNearbySearchApiClient.GetAsync(googleNearbyFoodInput);

            int counter = 1;

            foreach (var nr in nearbyFoodResults.results)
            {
                var details = await _googlePlaceDetailsApiClient.GetAsync(_googlePlaceDetailsInputFactory.CreateAllUseful(nr.place_id));

                if (details.IsOk)
                {
                    var candidate = new PlanElementCandidate(details.Result.name, details.Result.place_id, details.Result.formatted_address, details.Result.geometry.location, details.Result.opening_hours, details.Result.types, details.Result.rating, details.Result.price_level, details.Result.user_ratings_total);
                    if (test)
                    {
                        return(candidate);
                    }

                    candidates.Add(candidate);
                }
                ++counter;
                if (counter > 10 && candidates.Count > 5)
                {
                    break;
                }
            }



            var iter = 1;

            foreach (var candidate in candidates)
            {
                decisionRows.Add(_decisionRowFactory.Create(candidate, iter, iterParams.CurrentLocation));
                ++iter;
            }

            var minVector = DecisionArray.GetMinVector(decisionRows);
            var maxVector = DecisionArray.GetMaxVector(decisionRows);

            foreach (var decisionRow in decisionRows)
            {
                decisionRow.NormalizedScore = _sawMethod.CalculateNormalizedScore(SawNormalizationMethod.LinearFirstType, decisionArray.WeightVector, decisionRow.DecisionValues, minVector, maxVector);
            }

            var result = decisionRows.OrderByDescending(x => x.NormalizedScore).FirstOrDefault(x => x.Candidate.IsOpen(iterParams.CurrentDateTime));

            if (result == null)
            {
                throw new UserFriendlyException($"Nie udało się znaleźć żadnego miejsca, gdzie można zjeść w pobliżu o godz: {iterParams.CurrentDateTime}");
            }

            return(result.Candidate);
        }
        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);
        }