/// <summary>
        /// Execute HTTP request and read the response.
        /// </summary>
        /// <param name="request"></param>
        /// <returns>Formatted response from service.</returns>
        private RootRouteObject ExecuteAndRead(DriveReportTransportType transportType, HttpWebRequest request)
        {
            var responseString = "";

            Stream responseStream;

            try
            {
                var distanceResponse = request.GetResponse();
                responseStream = distanceResponse.GetResponseStream();
            }
            catch (WebException e)
            {
                var up = new RouteInformationException("Server error", e);
                //Logger.Error("Server error", up);
                throw up;
            }

            if (responseStream == null)
            {
                return(null);
            }

            var streamReader = new StreamReader(responseStream);

            responseString = streamReader.ReadToEnd();
            streamReader.Close();
            return(ParseJson(transportType, responseString));
        }
Esempio n. 2
0
        public double GetNDKWorkRouteCalculation(int employmentId, DriveReportTransportType transportType, bool startsHome, bool endsHome, Address[] addresses)
        {
            //Manipulate the list of adresses, so that we get the route for work instead of home.
            Employment employment = _employmentRepository.AsQueryable().Where(x => x.Id == employmentId).FirstOrDefault();

            if (employment == null)
            {
                return(-1);
            }
            Address workAddress;

            if (employment.AlternativeWorkAddress != null)
            {
                workAddress = employment.AlternativeWorkAddress;
            }
            else
            {
                workAddress = employment.OrgUnit.Address;
            }

            if (startsHome)
            {
                addresses[0] = workAddress;
            }
            if (endsHome)
            {
                addresses[addresses.Length - 1] = workAddress;
            }

            return(_route.GetRoute(transportType, addresses).Length);
        }
        /// <summary>
        /// Formats and structures the response.
        /// </summary>
        /// <param name="response"></param>
        /// <returns>Response reprensented in custom class.</returns>
        private RootRouteObject ParseJson(DriveReportTransportType transportType, string response)
        {
            JToken jRouteObject = JToken.Parse(response);

            if (jRouteObject == null)
            {
                return(null);
            }

            RootRouteObject route = new RootRouteObject(jRouteObject)
            {
                route_summary = new RouteSummary(jRouteObject["route_summary"])
            };

            if (jRouteObject["alternative_geometries"] != null)
            {
                if (jRouteObject["alternative_summaries"] != null)
                {
                    var altSums = jRouteObject["alternative_summaries"].ToList();

                    var altGeos = jRouteObject["alternative_geometries"].ToList();

                    for (int i = 0; i < altGeos.Count; i++)
                    {
                        route.alternative_geometries.Add((string)altGeos[i]);
                        route.alternative_summaries.Add(new AlternativeSummary(altSums[i]));
                    }
                }
            }

            if (jRouteObject["route_instructions"] != null)
            {
                var ferryDistance = 0;
                var list          = jRouteObject["route_instructions"].ToList();

                // Iterate all route instructions except for the last one.
                // The last one is different from the others somehow.
                // It does not have a mode. It only has 7 properties where the others have 8.
                // It never seems to have any distance though, so it shouldnt matter.
                for (var i = 0; i < list.Count - 1; i++)
                {
                    var currentInstruction = list.ElementAt(i).ToList();
                    var mode = currentInstruction.ElementAt(8).ToString();

                    // If the transportType is car mode 2 means travelling on a ferry.
                    // If the transportType is bicycle mode 3 means travelling on a ferry. Annoying that it's not mode 2 for both of them.
                    if ((transportType.Equals(DriveReportTransportType.Car) && mode == CarFerryMode) ||
                        (transportType.Equals(DriveReportTransportType.Bike) && mode == BicycleFerryMode))
                    {
                        // Replace "m" with nothing in the string, because the distance is given as "123m"
                        ferryDistance += int.Parse(currentInstruction.ElementAt(5).ToString().Replace("m", ""));
                    }
                }
                route.route_summary.distance_not_including_ferry = route.route_summary.total_distance - ferryDistance;
            }

            return(route);
        }
 public RouteInformation GetRoute(DriveReportTransportType transportType, IEnumerable <Address> addresses)
 {
     return(new RouteInformation()
     {
         Duration = 1337,
         EndStreet = "Katrinebjergvej 95, 8200 Aarhus",
         StartStreet = "Katrinebjergvej 40, 8200 Aarhus",
         GeoPoints = "",
         Length = 42
     });
 }
        /// <summary>
        /// Build query URL and create HTTP request following the service API url specifications.
        /// </summary>
        /// <param name="transportType">Type of transport. Car or Bike</param>
        /// <param name="routeCoordinates"></param>
        /// <returns></returns>
        private HttpWebRequest CreateRequest(DriveReportTransportType transportType, IEnumerable <Coordinates> routeCoordinates)
        {
            string      query = "";
            var         coordinateses = routeCoordinates as IList <Coordinates> ?? routeCoordinates.ToList();
            Coordinates origin, destination;

            try
            {
                origin      = coordinateses.Single(p => p.Type == Coordinates.CoordinatesType.Origin);
                destination = coordinateses.Single(p => p.Type == Coordinates.CoordinatesType.Destination);
            }
            catch (InvalidOperationException e)
            {
                var up = new RouteInformationException("Mutltiple coordinates with type Origin and/or Destination.", e);
                //Logger.Error("Multiple coordinates with type origin and/or destination", up);
                throw up;
            }

            if (origin == null || destination == null)
            {
                var up = new RouteInformationException("Coordinate of type Origin and/or Destination missing.");
                //Logger.Error("Coordinate of type Origin and/or destination missing.", up);
                throw up;
            }

            //if (!((origin.Latitude.Length - origin.Latitude.IndexOf(".") + 1) <= 5))
            //{
            //    origin.Latitude = origin.Latitude.Substring(0, origin.Latitude.IndexOf('.') + 1 + AddressCoordinates.CoordDecimals);
            //    origin.Longitude = origin.Longitude.Substring(0, origin.Longitude.IndexOf('.') + 1 + AddressCoordinates.CoordDecimals);
            //}

            query = "loc=" + origin.Latitude + "," + origin.Longitude;

            query = coordinateses.Where(p => p.Type == Coordinates.CoordinatesType.Via).Aggregate(query, (current, point) => current + ("&loc=" + point.Latitude + "," + point.Longitude));

            query += "loc=" + destination.Latitude + "," + destination.Longitude + "&instructions=true";

            switch (transportType)
            {
            case DriveReportTransportType.Car:
                return((HttpWebRequest)WebRequest.Create(UrlDefinitions.RoutingUrl + query));

            case DriveReportTransportType.Bike:
                return((HttpWebRequest)WebRequest.Create(UrlDefinitions.BikeRoutingUrl + query));
            }

            // Should never be reached
            return(null);
        }
        /// <summary>
        /// Get routes and alternative routes for the given set of coordinates.
        /// </summary>
        /// <param name="transportType">Type of transport. Car or Bike.</param>
        /// <param name="routeCoordinates"></param>
        /// <exception cref="RouteInformationException">Thrown if no route was returned or no rute was found.</exception>
        /// <returns></returns>
        public IEnumerable <RouteInformation> GetRoute(DriveReportTransportType transportType, IEnumerable <Coordinates> routeCoordinates)
        {
            List <RouteInformation> routes  = new List <RouteInformation>();
            HttpWebRequest          request = CreateRequest(transportType, routeCoordinates);
            RootRouteObject         result  = ExecuteAndRead(transportType, request);

            if (result == null)
            {
                var e = new RouteInformationException("No route returned.");
                //Logger.Error("Exception when getting route information", e);
                throw e;
            }


            //From septima 01/09 2016:
            //Routingservices kan forventes senere at returnere status = 200,
            //idet OSRM er gået fra at bruge "C style" exit-koder, til "HTTP Style" status-koder.
            if (result.status != 0 && result.status / 100 == 2)
            {
                var e = new RouteInformationException("No route found.");;
                //Logger.Error("Exception when getting route information", e);
                throw e;
            }

            var route = new RouteInformation();

            route.Length      = result.route_summary.distance_not_including_ferry;
            route.Duration    = result.route_summary.total_time;
            route.EndStreet   = result.route_summary.end_point;
            route.StartStreet = result.route_summary.start_point;
            route.GeoPoints   = result.route_geometry;

            routes.Add(route);
            for (int i = 0; i < result.alternative_summaries.Count; i++)
            {
                route = new RouteInformation
                {
                    Length      = result.alternative_summaries[i].total_distance,
                    Duration    = result.alternative_summaries[i].total_time,
                    EndStreet   = result.alternative_summaries[i].end_point,
                    StartStreet = result.alternative_summaries[i].start_point,
                    GeoPoints   = result.alternative_geometries[i]
                };

                routes.Add(route);
            }
            return(routes);
        }
Esempio n. 7
0
        /// <summary>
        /// Get routes and alternative routes for the given set of coordinates.
        /// </summary>
        /// <param name="transportType">Type of transport. Car or Bike.</param>
        /// <param name="routeCoordinates"></param>
        /// <exception cref="RouteInformationException">Thrown if no route was returned or no rute was found.</exception>
        /// <returns></returns>
        public IEnumerable <RouteInformation> GetRoute(DriveReportTransportType transportType, IEnumerable <Coordinates> routeCoordinates)
        {
            List <RouteInformation> routes  = new List <RouteInformation>();
            HttpWebRequest          request = CreateRequest(transportType, routeCoordinates);
            RootRouteObject         result  = ExecuteAndRead(transportType, request);

            if (result == null)
            {
                var e = new RouteInformationException("No route returned.");
                //Logger.Error("Exception when getting route information", e);
                throw e;
            }

            if (result.status != 0)
            {
                var e = new RouteInformationException("No route found.");;
                //Logger.Error("Exception when getting route information", e);
                throw e;
            }

            var route = new RouteInformation();

            route.Length      = result.route_summary.distance_not_including_ferry;
            route.Duration    = result.route_summary.total_time;
            route.EndStreet   = result.route_summary.end_point;
            route.StartStreet = result.route_summary.start_point;
            route.GeoPoints   = result.route_geometry;

            routes.Add(route);
            for (int i = 0; i < result.alternative_summaries.Count; i++)
            {
                route = new RouteInformation
                {
                    Length      = result.alternative_summaries[i].total_distance,
                    Duration    = result.alternative_summaries[i].total_time,
                    EndStreet   = result.alternative_summaries[i].end_point,
                    StartStreet = result.alternative_summaries[i].start_point,
                    GeoPoints   = result.alternative_geometries[i]
                };

                routes.Add(route);
            }
            return(routes);
        }
        public IHttpActionResult NDKWorkRouteCalculation(int employmentId, DriveReportTransportType transportType, bool startsHome, bool endsHome, [FromBody] Address[] addresses)
        {
            double result = 0.0;

            try
            {
                result = _driveReportService.GetNDKWorkRouteCalculation(employmentId, transportType, startsHome, endsHome, addresses);
            }
            catch (Exception e)
            {
                return(InternalServerError(e));
            }

            if (result < 0)
            {
                return(BadRequest());
            }

            return(Ok(result));
        }
Esempio n. 9
0
        /// <summary>
        /// Returns the shortest route within the time limit. (Duration <= 300s , Length difference > 3000m)
        /// </summary>
        /// <param name="transportType">Type of transport. Car or bike.</param>
        /// <param name="addresses"></param>
        /// <exception cref="AddressLaunderingException"></exception>
        /// <exception cref="AddressCoordinatesException"></exception>
        /// <exception cref="RouteInformationException"></exception>
        /// <returns></returns>
        public RouteInformation GetRoute(DriveReportTransportType transportType, IEnumerable <Address> addresses)
        {
            if (addresses == null || !addresses.Any())
            {
                return(null);
            }
            var addressesList = addresses.ToList();

            List <Coordinates> routeCoordinates = new List <Coordinates>();
            AddressCoordinates coordService     = new AddressCoordinates();
            SeptimaRouter      septimaService   = new SeptimaRouter();

            var origin      = addressesList[0];
            var destination = addressesList[addressesList.Count - 1];

            addressesList.Remove(origin);
            addressesList.Remove((destination));

            if (String.IsNullOrEmpty(origin.Longitude))
            {
                routeCoordinates.Add(coordService.GetCoordinates(origin, Coordinates.CoordinatesType.Origin));
            }
            else
            {
                routeCoordinates.Add(new Coordinates()
                {
                    Longitude = origin.Longitude,
                    Latitude  = origin.Latitude,
                    Type      = Coordinates.CoordinatesType.Origin
                });
            }

            foreach (var address in addressesList)
            {
                if (String.IsNullOrEmpty(address.Longitude))
                {
                    routeCoordinates.Add(coordService.GetCoordinates(address,
                                                                     Coordinates.CoordinatesType.Via));
                }
                else
                {
                    routeCoordinates.Add(new Coordinates()
                    {
                        Longitude = address.Longitude,
                        Latitude  = address.Latitude,
                        Type      = Coordinates.CoordinatesType.Via
                    });
                }
            }

            if (String.IsNullOrEmpty(destination.Longitude))
            {
                routeCoordinates.Add(coordService.GetCoordinates(destination, Coordinates.CoordinatesType.Destination));
            }
            else
            {
                routeCoordinates.Add(new Coordinates()
                {
                    Longitude = destination.Longitude,
                    Latitude  = destination.Latitude,
                    Type      = Coordinates.CoordinatesType.Destination
                });
            }

            try
            {
                List <RouteInformation> routes =
                    septimaService.GetRoute(transportType, routeCoordinates).OrderBy(x => x.Duration).ToList();

                // Sort routes by duration and pick the one with the shortest duration.
                // OS2RouteMap.js in the frontend picks the route with the shortest duration
                // Therefore the backend should pick a route based on the same criteria.
                routes = routes.OrderBy(x => x.Duration).ToList();
                var bestRoute = routes[0];

                // Divide by 1000 to get it in kilometers.
                bestRoute.Length /= 1000;
                return(bestRoute);
            }
            catch (AddressCoordinatesException e)
            {
                //Logger.Error("Exception when getting route information", e);
            }
            return(null);
        }
Esempio n. 10
0
        /// <summary>
        /// Takes a DriveReport as input and returns it with data.
        ///
        /// FourKmRule: If a user has set the FourKmRule to be used, the distance between
        /// the users home and municipality is used in the correction of the driven distance.
        /// If the rule is not used, the distance between the users home and work address are
        /// calculated and used, provided that the user has not set a override for this value.
        ///
        /// Calculated: The driven route is calculated, and based on whether the user starts
        /// and/or ends at home, the driven distance is corrected by subtracting the distance
        /// between the users home address and work address.
        /// Again, this is dependend on wheter the user has overridden this value.
        ///
        /// Calculated without extra distance: If this method is used, the driven distance is
        /// still calculated, but the distance is not corrected with the distance between the
        /// users home address and work address. The distance calculated from the service is
        /// therefore used directly in the calculation of the amount to reimburse
        ///
        /// </summary>
        public DriveReport Calculate(RouteInformation drivenRoute, DriveReport report)
        {
            //Check if user has manually provided a distance between home address and work address
            var homeWorkDistance = 0.0;

            var person = _personRepo.AsQueryable().First(x => x.Id == report.PersonId);

            var homeAddress = _personService.GetHomeAddress(person);

            // Get Work and Homeaddress of employment at time of DriveDateTimestamp for report.
            AddressHistory addressHistory = null;

            try
            {
                addressHistory = _addressHistoryRepo.AsQueryable().SingleOrDefault(x => x.EmploymentId == report.EmploymentId && x.StartTimestamp <report.DriveDateTimestamp && x.EndTimestamp> report.DriveDateTimestamp);
            }
            catch (InvalidOperationException)
            {
                _logger.LogForAdmin(report.FullName + " har et overlap i sin adressehistorik");
                throw;
            }

            if (homeAddress.Type != PersonalAddressType.AlternativeHome)
            {
                if (addressHistory != null && addressHistory.HomeAddress != null)
                {
                    // If user doesn't have an alternative address set up then use the homeaddress at the time of DriveDateTimestamp
                    // If the user does have an alternative address then always use that.
                    homeAddress = addressHistory.HomeAddress;
                }
            }


            var employment = _emplrepo.AsQueryable().FirstOrDefault(x => x.Id.Equals(report.EmploymentId));

            Address workAddress = employment.OrgUnit.Address;

            if (addressHistory != null && addressHistory.WorkAddress != null)
            {
                // If an AddressHistory.WorkAddress exists, then use that.
                workAddress = addressHistory.WorkAddress;
            }


            if (employment.AlternativeWorkAddress != null)
            {
                // Overwrite workaddress if an alternative work address exists.
                workAddress = employment.AlternativeWorkAddress;
            }

            if (report.KilometerAllowance != KilometerAllowance.Read && !report.IsFromApp)
            {
                //Check if drivereport starts at users home address.
                report.StartsAtHome = areAddressesCloseToEachOther(homeAddress, report.DriveReportPoints.First());
                //Check if drivereport ends at users home address.
                report.EndsAtHome = areAddressesCloseToEachOther(homeAddress, report.DriveReportPoints.Last());
            }


            homeWorkDistance = employment.WorkDistanceOverride;

            if (homeWorkDistance <= 0)
            {
                homeWorkDistance = _route.GetRoute(DriveReportTransportType.Car, new List <Address>()
                {
                    homeAddress, workAddress
                }).Length;
            }

            //Calculate distance to subtract
            //double toSubtract = 0;
            double toSubtractFourKmRule = 0;
            double toSubtractHomeRule   = 0;
            double toSubtractAltRule    = 0;


            //If user indicated to use the Four Km Rule
            if (report.FourKmRule)
            {
                //Take users provided distance from home to border of municipality. If report is from app, use distance provided in report, else use distance saved on person.
                var borderDistance = report.IsFromApp ? report.HomeToBorderDistance : person.DistanceFromHomeToBorder;

                //Adjust distance based on if user starts or ends at home
                if (report.StartsAtHome)
                {
                    //toSubtract += borderDistance;
                    toSubtractFourKmRule += borderDistance;
                }

                if (report.EndsAtHome)
                {
                    //toSubtract += borderDistance;
                    toSubtractFourKmRule += borderDistance;
                }
            }
            else
            {
                //Same logic as above, but uses calculated distance between home and work
                if (report.StartsAtHome)
                {
                    //toSubtract += homeWorkDistance;
                    toSubtractHomeRule += homeWorkDistance;
                }

                if (report.EndsAtHome)
                {
                    //toSubtract += homeWorkDistance;
                    toSubtractHomeRule += homeWorkDistance;
                }
            }

            switch (report.KilometerAllowance)
            {
            case KilometerAllowance.Calculated:
            {
                string alternativeCalculationMethod = ConfigurationManager.AppSettings["AlternativeCalculationMethod"];
                if (alternativeCalculationMethod == null)
                {
                    alternativeCalculationMethod = string.Empty;
                }
                // Use Norddjurs alternative reimbursemnt calculation method if configured so.
                if (alternativeCalculationMethod.ToLower() == "ndk")
                {
                    // Newer subtract the "daily" distance between HOME and WORK.
                    toSubtractHomeRule = 0.0;

                    // Get the drive report points.
                    List <DriveReportPoint> altDriveReportPoints = new List <DriveReportPoint>();
                    foreach (DriveReportPoint altDriveReportPoint in report.DriveReportPoints)
                    {
                        altDriveReportPoints.Add(altDriveReportPoint);
                    }

                    // Get if a bike is used for transportation.
                    Boolean altIsBike = _rateTypeRepo.AsQueryable().First(x => x.TFCode.Equals(report.TFCode)).IsBike;
                    DriveReportTransportType altTransportType = (altIsBike == true) ? DriveReportTransportType.Bike : DriveReportTransportType.Car;
                    Double altToSubtract1 = 0.0;
                    Double altToSubtract2 = 0.0;

                    // 1a. When starting from home
                    if (            //(report.IsFromApp == false) &&
                        (report.StartsAtHome == true) &&
                        (altDriveReportPoints.Count >= 2) &&
                        ((altDriveReportPoints[1].Latitude != workAddress.Latitude) && (altDriveReportPoints[1].Longitude != workAddress.Longitude)))
                    {
                        // A1) Get the distance between HOME and the first LOCATION (the route in the report).
                        //     This is used to select the reported route, or the alternative route.
                        List <Address> altAddressesToHome = new List <Address>();
                        altAddressesToHome.Add(homeAddress);
                        altAddressesToHome.Add(altDriveReportPoints[1]);
                        Double altDistanceToHome = _route.GetRoute(altTransportType, altAddressesToHome).Length;


                        // A2) Get the distance for the entire route (the route in the report).
                        //     This is used to calculate the distance to subtract.
                        altAddressesToHome = new List <Address>(altDriveReportPoints);
                        Double altDistanceA = _route.GetRoute(altTransportType, altAddressesToHome).Length;


                        // B1) Get the distance between WORK and the first LOCATION.
                        //     This is used to select the reported route, or the alternative route.
                        List <Address> altAddressesToWork = new List <Address>();
                        altAddressesToWork.Add(workAddress);
                        altAddressesToWork.Add(altDriveReportPoints[1]);
                        Double altDistanceToWork = _route.GetRoute(altTransportType, altAddressesToWork).Length;


                        // B2) Get the distance for the entire alternative route.
                        //     This is used to calculate the distance to subtract.
                        altAddressesToWork    = new List <Address>(altDriveReportPoints);
                        altAddressesToWork[0] = workAddress;
                        Double altDistanceB = _route.GetRoute(altTransportType, altAddressesToWork).Length;


                        // The current report distance is including the route between HOME and LOCATION.
                        // Substract the difference, if the distance between WORK and LOCATION is smaller.
                        if (altDistanceToWork < altDistanceToHome)
                        {
                            altToSubtract1 = (altDistanceA - altDistanceB);
                        }
                    }

                    // 1b. When starting from home
                    if (            //(report.IsFromApp == false) &&
                        (report.StartsAtHome == true) &&
                        (altDriveReportPoints.Count == 2) &&
                        ((altDriveReportPoints[1].Latitude == workAddress.Latitude) && (altDriveReportPoints[1].Longitude == workAddress.Longitude)))
                    {
                        toSubtractHomeRule += homeWorkDistance;
                    }


                    // 2a. When finishing at home
                    if (                //(report.IsFromApp == false) &&
                        (report.EndsAtHome == true) &&
                        (altDriveReportPoints.Count >= 2) &&
                        ((altDriveReportPoints[altDriveReportPoints.Count - 2].Latitude != workAddress.Latitude) && (altDriveReportPoints[altDriveReportPoints.Count - 2].Longitude != workAddress.Longitude)))
                    {
                        // A1) Get the distance between the second last LOCATION and HOME (the route in the report).
                        //     This is used to select the reported route, or the alternative route.
                        List <Address> altAddressesToHome = new List <Address>();
                        altAddressesToHome.Add(altDriveReportPoints[altDriveReportPoints.Count - 2]);
                        altAddressesToHome.Add(homeAddress);
                        Double altDistanceToHome = _route.GetRoute(altTransportType, altAddressesToHome).Length;


                        // A2) Get the distance for the entire route (the route in the report).
                        //     This is used to calculate the distance to subtract.
                        altAddressesToHome = new List <Address>(altDriveReportPoints);
                        Double altDistanceA = _route.GetRoute(altTransportType, altAddressesToHome).Length;


                        // B1) Get the distance between the second last LOCATION and WORK.
                        //     This is used to select the reported route, or the alternative route.
                        List <Address> altAddressesToWork = new List <Address>();
                        altAddressesToWork.Add(altDriveReportPoints[altDriveReportPoints.Count - 2]);
                        altAddressesToWork.Add(workAddress);
                        Double altDistanceToWork = _route.GetRoute(altTransportType, altAddressesToWork).Length;


                        // B2) Get the distance for the entire alternative route.
                        //     This is used to calculate the distance to subtract.
                        altAddressesToWork = new List <Address>(altDriveReportPoints);
                        altAddressesToWork[altAddressesToWork.Count - 1] = workAddress;
                        Double altDistanceB = _route.GetRoute(altTransportType, altAddressesToWork).Length;


                        // The current report distance is including the route between HOME and LOCATION.
                        // Substract the difference, if the distance between WORK and LOCATION is smaller.
                        if (altDistanceToWork < altDistanceToHome)
                        {
                            altToSubtract2 = (altDistanceA - altDistanceB);
                        }
                    }

                    // 2b. When finishing at home and 2 points and 1 is work
                    if (            //(report.IsFromApp == false) &&
                        (report.EndsAtHome == true) &&
                        (altDriveReportPoints.Count == 2) &&
                        ((altDriveReportPoints[altDriveReportPoints.Count - 2].Latitude == workAddress.Latitude) && (altDriveReportPoints[altDriveReportPoints.Count - 2].Longitude == workAddress.Longitude)))
                    {
                        toSubtractHomeRule += homeWorkDistance;
                    }

                    // Subtract.
                    toSubtractAltRule = altToSubtract1 + altToSubtract2;
                }
                //End NDK

                if ((report.StartsAtHome || report.EndsAtHome) && !report.FourKmRule)
                {
                    report.IsExtraDistance = true;
                }

                double drivenDistance = report.Distance;

                if (!report.IsFromApp)
                {
                    // In case the report is not from app then get distance from the supplied route.
                    drivenDistance = drivenRoute.Length;
                }
                //Adjust distance based on FourKmRule and if user start and/or ends at home
                //var correctDistance = drivenDistance - toSubtract;
                var correctDistance = drivenDistance - (toSubtractFourKmRule + toSubtractHomeRule + toSubtractAltRule);


                //Set distance to corrected
                report.Distance = correctDistance;

                if (!report.IsFromApp)
                {
                    //Get RouteGeometry from driven route if the report is not from app. If it is from App then RouteGeometry is already set.
                    report.RouteGeometry = drivenRoute.GeoPoints;
                }

                break;
            }

            case KilometerAllowance.CalculatedWithoutExtraDistance:
            {
                report.Distance = drivenRoute.Length;

                //Save RouteGeometry
                report.RouteGeometry = drivenRoute.GeoPoints;


                break;
            }

            case KilometerAllowance.Read:
            {
                if ((report.StartsAtHome || report.EndsAtHome) && !report.FourKmRule)
                {
                    report.IsExtraDistance = true;
                }

                //Take distance from report
                var manuallyProvidedDrivenDistance = report.Distance;

                //report.Distance = manuallyProvidedDrivenDistance - toSubtract;
                report.Distance = manuallyProvidedDrivenDistance - toSubtractFourKmRule - toSubtractHomeRule;

                break;
            }

            default:
            {
                throw new Exception("No calculation method provided");
            }
            }

            //Calculate the actual amount to reimburse

            if (report.Distance < 0)
            {
                report.Distance = 0;
            }

            // Multiply the distance by two if the report is a return trip
            if (report.IsRoundTrip == true)
            {
                report.Distance *= 2;
            }

            CalculateFourKmRuleForReport(report);

            SetAmountToReimburse(report);

            return(report);
        }