/// <summary>
        ///
        /// </summary>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <returns></returns>
        public static double GetDistance(this LngLatPoint from, LngLatPoint to)
        {
            var sCoord = new GeoCoordinate(from.Lat, from.Lng);
            var eCoord = new GeoCoordinate(to.Lat, to.Lng);

            return(sCoord.GetDistanceTo(eCoord));
        }
 public static double[] ToDblArr(this LngLatPoint lngLatPoint)
 {
     return(new[] { lngLatPoint.Lng, lngLatPoint.Lat });
 }
        /// <summary>
        ///
        /// </summary>
        /// <param name="path"></param>
        /// <param name="locations"></param>
        /// <returns></returns>
        private static Tuple <IEnumerable <Activity>, List <RoutePoint> > CalculateActivitiesAndWpCoords(RouteResponsePath path, IReadOnlyList <Location> locations)
        {
            var activities = new List <Activity>();
            var points     = path.Points;
            var snappedPts = path.SnappedWaypoints;
            var times      = path.Details.Times;
            var wpCoords   = new List <RoutePoint>();

            Func <Location, ResponseCoordinatesArray, int, Tuple <int, LngLatPoint> > findClosest = (loc, coords, skpIdx) =>
            {
                try
                {
                    var lc = coords
                             .Skip(skpIdx)
                             .OrderBy(p => loc.ToLngLatPoint()
                                      .GetDistance(new LngLatPoint()
                    {
                        Lng = p[0] ?? 0,
                        Lat = p[1] ?? 0
                    }))
                             .FirstOrDefault();
                    var idx = coords.FindIndex(p => p.Equals(lc));
                    return(new Tuple <int, LngLatPoint>(idx, new LngLatPoint()
                    {
                        Lng = lc[0] ?? 0,
                        Lat = lc[1] ?? 0
                    }));
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            };

            Func <int, int, ResponseCoordinatesArray, Tuple <double, long, RoutePoint> > computeTotTimeAndDistance = (frmIdx, toIdx, coords) =>
            {
                try
                {
                    var src  = coords.Skip(frmIdx).Take(toIdx - frmIdx).ToArray();
                    var dist = 0.0;
                    var wps  = new RoutePoint();

                    for (var i = 0; i < src.Count(); i++)
                    {
                        var ths = src[i];
                        wps.Coordinates.Add(new[] { ths[0] ?? 0.0, ths[1] ?? 0.0 });

                        if (i == 0)
                        {
                            continue;
                        }
                        var prv = src[i - 1];

                        // compute for the distance
                        var srcPt = new LngLatPoint(prv[0], prv[1]);
                        var dstPt = new LngLatPoint(ths[0], ths[1]);
                        dist += srcPt.GetDistance(dstPt);
                    }

                    // compute total travel time
                    var tmSrc   = times.Where(p => p[0] >= frmIdx && p[1] < toIdx);
                    var totSecs = tmSrc.Sum(s => s[2]);

                    return(new Tuple <double, long, RoutePoint>(dist, totSecs ?? 0, wps));
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            };

            Tuple <int, LngLatPoint> lstClosest = null;

            for (var i = 0; i < locations.Count; i++)
            {
                try
                {
                    var loc = locations[i];

                    if (i == 0)
                    {
                        activities.Add(new Activity(Activity.TypeEnum.Start, loc.LocationId, loc.LocationId));
                    }
                    else
                    {
                        var closest           = findClosest(loc, points.Coordinates, lstClosest?.Item1 ?? 0);
                        var tupDistTimeCoords = computeTotTimeAndDistance(lstClosest?.Item1 ?? 0, closest.Item1, points.Coordinates);
                        var type = (i == (locations.Count - 1)) ? Activity.TypeEnum.End : Activity.TypeEnum.Service;
                        activities.Add(new Activity(id: loc.LocationId,
                                                    type: type,
                                                    locationId: loc.LocationId,
                                                    arrTime: tupDistTimeCoords.Item2 / 1000,
                                                    drivingTime: tupDistTimeCoords.Item2 / 1000,
                                                    endTime: tupDistTimeCoords.Item2 / 1000,
                                                    waitingTime: 0,
                                                    distance: tupDistTimeCoords.Item1));

                        wpCoords.Add(tupDistTimeCoords.Item3);
                        lstClosest = closest;
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            }
            return(new Tuple <IEnumerable <Activity>, List <RoutePoint> >(activities, wpCoords));
        }