public RouteAssignment assignMultipleRoutes(List <Route> routes, List <Driver> drivers)
        {
            var           tempRouteData = new List <TempRoute>();
            List <Driver> alreadyAssignedDriversForADay           = new List <Driver>();
            List <Driver> driversAlreadyAssignedARouteThisSession = new List <Driver>();
            Route         prevRoute    = null;
            List <Route>  sortedRoutes = routes.OrderByDescending(r => r.DeliverBy).ToList();

            foreach (Route route in sortedRoutes)
            {
                if (prevRoute != null && !prevRoute.DeliverBy.Equals(route.DeliverBy))
                {
                    alreadyAssignedDriversForADay.Clear();
                }
                DriverAssignmentResult assignmentResult = getBestDriverForRoute(route, drivers, alreadyAssignedDriversForADay, driversAlreadyAssignedARouteThisSession, route.DeliverBy);
                TempRoute parameters = new TempRoute();
                parameters.DriversVehicle        = assignmentResult.Vehicle;
                parameters.ModifiedDeliverByDate = assignmentResult.DeliverByDate;
                parameters.Driver  = assignmentResult.Driver;
                parameters.RouteId = route.ID;
                alreadyAssignedDriversForADay.Add(assignmentResult.Driver);
                tempRouteData.Add(parameters);
                prevRoute = route;
                driversAlreadyAssignedARouteThisSession.Add(assignmentResult.Driver);
            }
            RouteAssignment assignemnt = new RouteAssignment();

            assignemnt.Routes        = routes;
            assignemnt.TempRouteData = tempRouteData;
            return(assignemnt);
        }
        public DriverAssignmentResult getBestDriverForRoute(Route route, List <Driver> drivers, List <Driver> unavailableDrivers, List <Driver> driversAlreadyAssignedRoutesInThisSession, DateTime DeliverBy)
        {
            DriverAssignmentResult[] assignmentCosts          = new DriverAssignmentResult[drivers.Count()];
            List <Driver>            copyOfUnavailableDrivers = unavailableDrivers.ToList();


            List <Driver> sortedDriverList = sortDiversInTheOrderOfBusiness(drivers.ToList(), copyOfUnavailableDrivers);

            foreach (Driver driver in sortedDriverList)
            {
                if (!unavailableDrivers.Contains(driver))
                {
                    DriverAssignmentResult result = getCostForDriverBeingAssignedToRoute(driver, route, DeliverBy);
                    assignmentCosts[drivers.IndexOf(driver)] = result;
                }
                else
                {
                    DriverAssignmentResult result = new DriverAssignmentResult();
                    result.DeliverByDate = DeliverBy;
                    result.RouteID       = route.ID;
                    assignmentCosts[drivers.IndexOf(driver)] = result;
                }
            }

            List <DriverAssignmentResult> results        = assignmentCosts.OrderByDescending(i => i.AssignmentProfit).ToList();
            DriverAssignmentResult        maxValueResult = results.FirstOrDefault();

            if (maxValueResult != null && maxValueResult.AssignmentProfit != 0)
            {
                var result = getBestResult(results, driversAlreadyAssignedRoutesInThisSession);
                if (result == null)
                {
                    return(maxValueResult); //if everyone has been assigned smth, then we can only select the one that is the best in terms of profit
                }
                else
                {
                    return(result);
                }
            }

            else
            {
                if (numberOfTries < 3)
                {
                    numberOfTries++;
                    DateTime deliverBy = route.DeliverBy.AddDays(-numberOfTries);
                    return(getBestDriverForRoute(route, drivers, unavailableDrivers, driversAlreadyAssignedRoutesInThisSession, deliverBy));
                }
                else
                {
                    DriverAssignmentResult result = new DriverAssignmentResult();
                    result.DeliverByDate = route.DeliverBy;
                    result.RouteID       = route.ID;
                    return(result);
                }
            }
        }
        public void testDriverSelectionWhenBothDriversAreNotAvailable()
        {
            Driver driverOne = new Driver();

            driverOne.Address = new DriverAddress();
            Vehicle vehicleOne = new Vehicle(300, 100, 109, 100);

            driverOne.Vehicles.Add(vehicleOne);
            Route driverRoute = new Route();

            driverRoute.DeliverBy = new DateTime(2015, 12, 12);
            driverOne.Routes.Add(driverRoute);


            Driver driverTwo = new Driver();

            driverTwo.Address = new DriverAddress();
            driverTwo.Vehicles.Add(vehicleOne);
            driverTwo.Address = (DriverAddress)getAddress(true);
            List <Driver> drivers = new List <Driver> {
                driverOne, driverTwo
            };

            driverTwo.Routes.Add(driverRoute);

            var responseMessageOne = new HttpResponseMessage();

            responseMessageOne.Content = new StringContent("{\"destination_addresses\":[\"Village Way, Brighton BN1, United Kingdom\"],\"origin_addresses\":[\"Arts Rd, Falmer, Brighton BN1 9QN, United Kingdom\"],\"rows\":[{\"elements\":[{\"distance\":{\"text\":\"0.8 mi\",\"value\":2},\"duration\":{\"text\":\"4 min\",\"value\":235},\"status\":\"OK\"}]}],\"status\":\"OK\"}");

            var responseMessageTwo = new HttpResponseMessage();

            responseMessageTwo.Content = new StringContent("{\"destination_addresses\":[\"Village Way, Brighton BN1, United Kingdom\"],\"origin_addresses\":[\"Arts Rd, Falmer, Brighton BN1 9QN, United Kingdom\"],\"rows\":[{\"elements\":[{\"distance\":{\"text\":\"3.6 mi\",\"value\":10},\"duration\":{\"text\":\"4 min\",\"value\":235},\"status\":\"OK\"}]}],\"status\":\"OK\"}");
            List <HttpResponseMessage> responses = new List <HttpResponseMessage> {
                responseMessageOne, responseMessageTwo
            };
            TestGoogleMapsUtil googleMaps = new TestGoogleMapsUtil(responses);

            Route route = new Route();

            route.DeliverBy     = new DateTime(2015, 12, 13);
            route.PickUpAddress = (PickUpAddress)getAddress(false);
            Delivery delivery = new Delivery();

            delivery.ItemWeight = 20;
            delivery.ItemSize   = ItemSize.Small;
            route.Deliveries.Add(delivery);

            LocationService         locationService   = new LocationService(googleMaps);
            DriverAssignmentService assignmentService = new DriverAssignmentService(locationService);

            DriverAssignmentResult result = assignmentService.getBestDriverForRoute(route, drivers, new List <Driver>(), new List <Driver>(), new DateTime(2015, 12, 12));

            Assert.Equal(result.Driver, driverOne);
            Assert.Equal(result.DeliverByDate, new DateTime(2015, 12, 13));
        }
        private DriverAssignmentResult getBestResult(List <DriverAssignmentResult> results, List <Driver> alreadyBusyDrivers)
        {
            DriverAssignmentResult firstResult = results.FirstOrDefault();

            if (firstResult != null && firstResult.AssignmentProfit != 0 && !alreadyBusyDrivers.Contains(firstResult.Driver))
            {
                return(firstResult);
            }
            else if (results.Count() >= 1)
            {
                return(getBestResult(results.GetRange(1, results.Count() - 1), alreadyBusyDrivers));
            }
            else
            {
                return(null);
            }
        }
        private DriverAssignmentResult getCostForDriverBeingAssignedToRoute(Driver driver, Route route, DateTime DeliverBy)
        {
            double profit = 0;
            DriverAssignmentResult result = new DriverAssignmentResult(route.ID, route.DeliverBy, driver);

            if (driverIsOnHoliday(driver, DeliverBy))
            {
                result.AssignmentProfit = 0;
                return(result);
            }
            //if there is already a delivery on a day before deliveryby day
            if (driver.Routes.Where(r => r.DeliverBy.Equals(DeliverBy.AddDays(-1))).ToList().Count() != 0)
            {
                // return 0; //ifdriver is not available on a day, no need to check other
                result.AssignmentProfit = 0;
                return(result);
            }
            else
            {
                profit += 5;
            }

            double weightOfDeliveriesInRoute = 0;
            double capacityOfBoxes           = 0;

            for (int i = 0; i < route.Deliveries.Count(); i++)
            {
                Delivery delivery = route.Deliveries.ElementAt(i);
                weightOfDeliveriesInRoute += delivery.ItemWeight;
                capacityOfBoxes           += calculateCapacity(ItemSizeDimensionsExtension.getItemDimensionsBasedOnSize(delivery.ItemSize));
            }

            Vehicle suitableVehicle = null;

            for (int i = 0; i < driver.Vehicles.Count(); i++)
            {
                Vehicle vehicle = driver.Vehicles.ElementAt(i);
                if (capacityOfBoxes <= calculateCapacity(new DeliveryItemDimensions(vehicle.Height, vehicle.Width, vehicle.Length)) && vehicle.MaxLoad >= weightOfDeliveriesInRoute)
                {
                    suitableVehicle = vehicle;
                    break;
                }
            }

            //add 0 weight if there is no
            if (suitableVehicle == null)
            {
                result.AssignmentProfit = 0;
                return(result);
                //if no vehicle available then no point looking further
            }
            else
            {
                result.Vehicle = suitableVehicle;
                profit        += 5;
            }
            var distanceFromDepotLocation = locationService.getDistanceBetweenTwoAddresses(driver.Address, route.PickUpAddress).Result;

            profit += 100 / distanceFromDepotLocation;
            result.AssignmentProfit = profit;
            return(result);
        }