public GeocacheRoutingInformation(GeocacheRoutingInformation ObjectToCopy)
 {
     geocache               = ObjectToCopy.geocache;
     DistanceToRoute        = ObjectToCopy.DistanceToRoute;
     EstimatedExtraDistance = ObjectToCopy.EstimatedExtraDistance;
     ResolvedCoordinates    = ObjectToCopy.ResolvedCoordinates;
 }
        private RouteData FillRouteWithGeocachesUntilMaxDistanceIsReached(RouteData CompleteRouteData)
        {
            Fileoperations.Routerlog.AddSubSection("Entered filling route with geocaches");
            //TODO Make MaxDistance to meters as well
            ///////////////////////////////////////////////////////////////////////////////////////
            //TAKE CARE RouteDistance is in m, MaxDistance in km!!!
            ////////////////////////////////////////////////////////////////////////////////

            GeocacheRoutingInformation GeocacheToAdd = null;

            do
            {
                //Values
                GeocacheToAdd = null;
                Route RouteToInsertIn        = null;
                int   IndexOfRouteToInsertIn = -1;

                #region Filter Geocaches

                /*Remove all Caches that definitely are not in Range (estimated distance, which is the shortest possible distance, bigger than distance set).
                 * Meanwhile find best rated geocache and the route it is the closest to.
                 * Only allow apercentage of the distance set, as the roads are most definitely not straight.
                 * For the case they are, there is another routine that picks up the caches that are directly on the route.
                 */
                Parallel.For(0, CompleteRouteData.partialRoutes.Count, CurrentPartialRouteIndex =>
                {
                    PartialRoute CurrentPartialRoute = CompleteRouteData.partialRoutes[CurrentPartialRouteIndex];
                    List <GeocacheRoutingInformation> GeocachesToRemove = new List <GeocacheRoutingInformation>();
                    foreach (GeocacheRoutingInformation CurrentGeocache in CurrentPartialRoute.GeocachesInReach)
                    {
                        if (CurrentGeocache.EstimatedExtraDistance > (CompleteRouteData.Profile.MaxDistance * 1000 - CompleteRouteData.TotalDistance))
                        {
                            GeocachesToRemove.Add(CurrentGeocache);
                        }
                        else if (CompleteRouteData.GeocachesOnRoute().Contains(CurrentGeocache.geocache))
                        {
                            GeocachesToRemove.Add(CurrentGeocache);
                        }
                        else if (CurrentGeocache.EstimatedExtraDistance < CompleteRouteData.Profile.MaxDistance * 1000 - CompleteRouteData.TotalDistance)
                        {
                            /* If no cache is set as next geocache to insert
                             * If the cache we stumbled accross has more routingpoints than the old cache
                             */
                            if (GeocacheToAdd == null || CurrentGeocache.RoutingPoints > GeocacheToAdd.RoutingPoints)
                            {
                                lock (GeocacheToAddLocker)                                 //Since one can't lock GeocacheToAdd directly, since it is not the same object that is locked and unlocked
                                {
                                    GeocacheToAdd = CurrentGeocache;
                                }
                                lock (RouteToInsertInLocker)                                 //See above
                                {
                                    RouteToInsertIn = CurrentPartialRoute.partialRoute;
                                }
                                IndexOfRouteToInsertIn = CurrentPartialRouteIndex;
                            }
                        }
                    }

                    //Remove all geocaches that can't be reached or are already used
                    foreach (GeocacheRoutingInformation Geocache_Info in GeocachesToRemove)
                    {
                        CurrentPartialRoute.GeocachesInReach.Remove(Geocache_Info);
                    }
                });
                #endregion
                //Won't be able to fit a geocache in
                if (CompleteRouteData.TotalTime + CompleteRouteData.Profile.TimePerGeocache * 60 > CompleteRouteData.Profile.MaxTime * 60)
                {
                    GeocacheToAdd = null;
                }

                if (GeocacheToAdd != null)
                {
                    Result <Tuple <Route, Route> > RoutingResult = GetPartialRoutes(CompleteRouteData, RouteToInsertIn, GeocacheToAdd.ResolvedCoordinates);

                    if (!RoutingResult.IsError)
                    {
                        float NewDistance          = CompleteRouteData.TotalDistance - RouteToInsertIn.TotalDistance + RoutingResult.Value.Item1.TotalDistance + RoutingResult.Value.Item2.TotalDistance;
                        float NewTimeWithGeocaches = CompleteRouteData.TotalTime - RouteToInsertIn.TotalTime + RoutingResult.Value.Item1.TotalTime + RoutingResult.Value.Item2.TotalTime + (CompleteRouteData.GeocachesOnRoute().Count + 1) * CompleteRouteData.Profile.TimePerGeocache * 60;
                        float NewRoutePoints       = CompleteRouteData.TotalPoints + GeocacheToAdd.geocache.Rating;

                        //calculate in meters
                        if (NewDistance < CompleteRouteData.Profile.MaxDistance * 1000 && NewTimeWithGeocaches < CompleteRouteData.Profile.MaxTime * 60)
                        {
                            Debug.WriteLine("Added " + GeocacheToAdd.geocache);
                            CompleteRouteData = ReplaceRoute(CompleteRouteData, RoutingResult.Value.Item1, RoutingResult.Value.Item2, IndexOfRouteToInsertIn);
                            CompleteRouteData.AddGeocacheOnRoute(GeocacheToAdd.geocache);
                            CompleteRouteData.TotalPoints = NewRoutePoints;                            //Overwrites the addition automatically made in the lne before, to make sure the
                            DisplayPreliminaryRoute(CompleteRouteData);
                        }
                        else
                        {
                            Debug.WriteLine("Made calculation for nothing. Route was longer in distance or time than allowed");
                            CompleteRouteData.partialRoutes[IndexOfRouteToInsertIn].GeocachesInReach.Remove(GeocacheToAdd);                            //As the geocache doesn't help from this route
                        }
                    }
                    else
                    {
                        Debug.WriteLine("Routing was errounous. Island detection score:" + FailedRouteCalculations);
                        CompleteRouteData.partialRoutes[IndexOfRouteToInsertIn].GeocachesInReach.Remove(GeocacheToAdd);                        //Since trying to route to it results in an error
                    }
                }
            } while (FailedRouteCalculations < FailedRouteCalculationsLimit && GeocacheToAdd != null);

            return(CompleteRouteData);
        }
        private RouteData DirectionDecision(RouteData CompleteRouteData, List <Geocache> GeocachesToConsider)
        {
            GeocachesToConsider = GeocachesToConsider.OrderByDescending(x => x.Rating).ToList();

            List <RouteData> Suggestions = new List <RouteData>();

            int NumberofRouteslongerthanlimit = 0;

            int FirstGeocacheNotUsedAsSuggestionBase = Program.DB.RoutefindingWidth + 1;

            try
            {
                Parallel.For(0, Program.DB.RoutefindingWidth, NumberOfSuggestions =>
                {
                    Fileoperations.Routerlog.LogCollector Log = new Fileoperations.Routerlog.LogCollector("DirectionDecision" + NumberOfSuggestions);

                    RouteData SuggestionRouteData;
                    lock (CompleteRouteData)
                    {
                        SuggestionRouteData = CompleteRouteData.DeepCopy();
                    }
                    lock (Suggestions)
                    {
                        Suggestions.Add(SuggestionRouteData);
                    }

                    int SuggestedCacheIndex = NumberOfSuggestions;

                    //Add geocaches to suggested route, as long as the route is shorter than the min allowed length, but also make sure it doesn't get too long in time and distance
                    while (SuggestionRouteData.TotalDistance < Program.DB.PercentageOfDistanceInAutoTargetselection_Min * SuggestionRouteData.Profile.MaxDistance * 1000 && SuggestedCacheIndex < GeocachesToConsider.Count)
                    {
                        Geocache SuggestedCache = GeocachesToConsider[SuggestedCacheIndex];
                        Log.AddMainInformation("Suggested " + SuggestedCache + " at Index Position " + SuggestedCacheIndex);

                        #region Find shortest resulting route if cache is inserted Route
                        int IndexOfRouteToInsertIn         = 0;
                        float MinEstimatedExtraRouteLength = -1;
                        for (int PartialRouteIndex = 0; PartialRouteIndex < SuggestionRouteData.partialRoutes.Count; PartialRouteIndex++)                   //Thus each partial route
                        {
                            float Length = GetEstimatedExtraDistance(SuggestionRouteData.partialRoutes[PartialRouteIndex].partialRoute, new Coordinate(SuggestedCache.lat, SuggestedCache.lon));
                            //Whether this is the route the geocache is currently closest to
                            if (MinEstimatedExtraRouteLength < 0 || Length < MinEstimatedExtraRouteLength)
                            {
                                IndexOfRouteToInsertIn       = PartialRouteIndex;
                                MinEstimatedExtraRouteLength = Length;
                            }
                        }
                        #endregion

                        Log.AddSubInformation("Estimated Route length: " + MinEstimatedExtraRouteLength);

                        //Check if the Cache seems to be in range. Error_Percentage * Max_Percentage * Remaining Distance, since the roads to the cache are quite surely not in a straight line and we want to fill up to the percentage only
                        if (MinEstimatedExtraRouteLength < Program.DB.PercentageOfDistanceInAutoTargetselection_Max * (SuggestionRouteData.Profile.MaxDistance * 1000 - SuggestionRouteData.TotalDistance))
                        {
                            Result <RouterPoint> GeocacheToAddResolveResult = Router1.TryResolve(SuggestionRouteData.Profile.ItineroProfile.profile, SuggestedCache.lat, SuggestedCache.lon, SearchDistanceInMeters);
                            Route RouteToInsertIn = SuggestionRouteData.partialRoutes[IndexOfRouteToInsertIn].partialRoute;

                            GeocacheRoutingInformation SuggestionBaseCache_Info;
                            if (!GeocacheToAddResolveResult.IsError)
                            {
                                SuggestionBaseCache_Info = new GeocacheRoutingInformation(SuggestedCache, MinEstimatedExtraRouteLength, GeocacheToAddResolveResult.Value);

                                Result <Tuple <Route, Route> > RoutingResult = GetPartialRoutes(SuggestionRouteData, RouteToInsertIn, SuggestionBaseCache_Info.ResolvedCoordinates);
                                if (!RoutingResult.IsError)
                                {
                                    // So one doesn't have to iterate through all routes
                                    //TestRouteDistance, as one doesn't know wether this on is taken
                                    float NewDistance = SuggestionRouteData.TotalDistance - RouteToInsertIn.TotalDistance + RoutingResult.Value.Item1.TotalDistance + RoutingResult.Value.Item1.TotalDistance;
                                    float NewTime     = SuggestionRouteData.TotalTime - RouteToInsertIn.TotalTime + RoutingResult.Value.Item1.TotalTime + RoutingResult.Value.Item1.TotalTime;

                                    if (NewDistance < Program.DB.PercentageOfDistanceInAutoTargetselection_Max * SuggestionRouteData.Profile.MaxDistance * 1000 && NewTime < Program.DB.PercentageOfDistanceInAutoTargetselection_Max * SuggestionRouteData.Profile.MaxTime * 60)
                                    {
                                        Log.AddSubInformation("Added the Geocache to the Route. New Distance:" + NewDistance);
                                        SuggestionRouteData = ReplaceRoute(SuggestionRouteData, RoutingResult.Value.Item1, RoutingResult.Value.Item2, IndexOfRouteToInsertIn);
                                        SuggestionRouteData.AddGeocacheOnRoute(SuggestedCache);
                                    }                               //Else just skip this cache.
                                    else
                                    {
                                        Log.AddSubInformation("The Resulting Distance was too long");
                                        NumberofRouteslongerthanlimit++;
                                    }
                                }
                            }
                            else                        //Couldn't resolve
                            {
                                Log.AddSubInformation("Couldn't resolve Geocache");
                                if (SuggestedCacheIndex == FirstGeocacheNotUsedAsSuggestionBase)
                                {
                                    FirstGeocacheNotUsedAsSuggestionBase++;                               //To avoid using the same cache as base twice
                                    SuggestedCacheIndex = FirstGeocacheNotUsedAsSuggestionBase--;         //Since ++ will happen
                                }
                                lock (GeocachesToConsider)
                                {
                                    GeocachesToConsider.RemoveAt(SuggestedCacheIndex);                               //Since it will never be possible to resolve it
                                }
                            }
                        }
                        else
                        {
                            Log.AddSubInformation("Estimated Distance was too long");
                        }

                        if (FailedRouteCalculations > FailedRouteCalculationsLimit)
                        {
                            break;
                        }
                        else
                        {
                            SuggestedCacheIndex++;
                        }
                    }

                    Log.Write();                // Since this thread is done
                });
            }
            catch (Exception)
            {
                Fileoperations.Routerlog.AddSubInformation("At least one exception has been caused.");
            }
            Fileoperations.Routerlog.AddSubInformation(NumberofRouteslongerthanlimit + " Routes have been to long.");

            if (Suggestions.Count != 0)
            {
                //Return best suggestion
                return(Suggestions.Find(x => x.TotalPoints == Suggestions.Max(y => y.TotalPoints)));
            }
            //If no suggestion has been found, just return the uncanged original Data
            return(CompleteRouteData);
        }