public override Solution executeStrategy(Solution toStartFrom)
        {
            var dayArray = Enum.GetValues(typeof(Days));
            Days day = (Days)dayArray.GetValue(random.Next(1, dayArray.Length));
            if (day.Equals(Days.None))
                Console.WriteLine("Day is Days.None at RouteAddStrategy! FIX ME!");

            routeCreated = new Route(day);
            var allClusters = toStartFrom.GetAllClusters();
            int clusterIndex = random.Next(allClusters.Count);

            for (int i = 0; i < 16; i++) //64 -> 16
            {
                clusterIndex = random.Next(allClusters.Count);
                if (allClusters[clusterIndex].AvailableOrdersInCluster.Count == 0)
                    continue;

                int randomIndex = random.Next(allClusters[clusterIndex].AvailableOrdersInCluster.Count);
                Order order = allClusters[clusterIndex].AvailableOrdersInCluster[randomIndex];

                if (!routeCreated.CanAddOrder(order))
                    continue;

                routeCreated.AddOrder(order);
                order.RemoveAvailableOrderFromCluster();
            }

            if (routeCreated.Orders.Count > 1) // Does the route have orders added to it
            {
                toStartFrom.AddRoute(routeCreated);
                strategyHasExecuted = true;
            }

            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            Solution toReturn = toStartFrom.GetShallowCopy();

            Day randomDay = toReturn.GetDays()[random.Next(toReturn.GetDays().Length)];

            List<Route> randomRoutes = randomDay.GetRoutes(random.Next(Day.NUMBER_OF_TRUCKS));
            Route randomChosenRoute = randomRoutes[random.Next(randomRoutes.Count)];
            List<Order> orders = randomChosenRoute.Orders;

            int ordersLength = orders.Count;
            int orderIndex1 = random.Next(1, ordersLength);
            int orderIndex2 = -1;
            do
            {
                orderIndex2 = random.Next(1, ordersLength);
            } while (!(orderIndex2 >= 0 && orderIndex2 != orderIndex1));

            Order toSwitch = orders[orderIndex1];
            Order toSwitch2 = orders[orderIndex2];

            Order toAddAfter = orders[orderIndex1 - 1];
            Order toAddAfter2 = orders[orderIndex2 - 1];

            randomChosenRoute.RemoveOrder(toSwitch, toReturn.GetOrdersCounter());
            randomChosenRoute.RemoveOrder(toSwitch2, toReturn.GetOrdersCounter());
            randomChosenRoute.AddOrder(toSwitch, toAddAfter2, toReturn.GetOrdersCounter());
            randomChosenRoute.AddOrder(toSwitch, toAddAfter, toReturn.GetOrdersCounter());

            return toReturn;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            Planning = toStartFrom.GetRandomPlanning();
            if (Planning.Item3.Count == 0)
                return toStartFrom;

            OriginalRoute = Planning.Item3[random.Next(Planning.Item3.Count)];
            if (OriginalRoute == null || OriginalRoute.Orders.Count < 2)
                return toStartFrom;

            int orderIndex = random.Next(OriginalRoute.Orders.Count - 1);
            OrderRemoved = OriginalRoute.Orders[orderIndex];
            OrderBefore = orderIndex == 0 ? null : OriginalRoute.Orders[orderIndex - 1];
            OrderRemoved.AddAvailableOrderBackToCluster();
            OriginalRoute.RemoveOrder(OrderRemoved);

            if (OriginalRoute.Orders.Count == 1)
            { // Basically delete the route (remove it from planning)
                toStartFrom.RemoveRouteFromPlanning(Planning.Item1, Planning.Item2, OriginalRoute);
                toStartFrom.RemoveRoute(OriginalRoute);
            }

            strategyHasExecuted = true;
            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            if (!strategyHasExecuted)
                return toStartFrom;

            toStartFrom.RemoveRouteFromPlanning(Planning.Item1, Planning.Item2, routePlanned);

            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            if (!strategyHasExecuted)
                return toStartFrom;

            toStartFrom.AddRouteToPlanning(Planning.Item1, Planning.Item2, routeDeleted);

            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            Planning = toStartFrom.GetRandomPlanning();
            RoutesFromSolution = Planning.Item3;

            //save the begin route for rollback
            old_route = RoutesFromSolution[random.Next(RoutesFromSolution.Count)];

            //copy the begin route for the 2-opt and create the route for the 2-opt check
            routeToWorkWith = new Route(Planning.Item1);
            new_route = new Route(Planning.Item1);
            foreach (Order order in old_route.Orders)
            {
                routeToWorkWith.AddOrder(order);
                new_route.AddOrder(order);
            }

            //start doing the opt-2 algorithm on the route list
            double best_traveltime = old_route.TravelTime;
            double new_traveltime = double.MaxValue;

            int improvestep = 0;
            while (improvestep < 50)
            {
                for (int i = 0; i < routeToWorkWith.Orders.Count - 2; i++)
                {
                    for (int k = i + 1; k < routeToWorkWith.Orders.Count - 1; k++)
                    {
                        //swap the 2 coords
                        swapOrders(routeToWorkWith.Orders[i], routeToWorkWith.Orders[k], routeToWorkWith);
                        new_traveltime = routeToWorkWith.TravelTime;
                        if (new_traveltime < best_traveltime)
                        {
                            improvestep = 0;
                            new_route = routeToWorkWith;
                            best_traveltime = new_traveltime;

                            routeToWorkWith = new Route(Planning.Item1);
                            foreach (Order order in new_route.Orders)
                                routeToWorkWith.AddOrder(order);
                        }
                    }
                }

                improvestep++;
            }

            RoutesFromSolution.Remove(old_route);
            RoutesFromSolution.Add(new_route);

            toStartFrom.RemoveItemFromPlanning(Planning.Item1, Planning.Item2);
            toStartFrom.AddNewItemToPlanning(Planning.Item1, Planning.Item2, RoutesFromSolution);

            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            if (!strategyHasExecuted)
                return toStartFrom;

                toStartFrom.AddRoute(old_route);
                toStartFrom.RemoveRouteFromPlanning(Planning.Item1, Planning.Item2, new_route);
                toStartFrom.AddRouteToPlanning(Planning.Item1, Planning.Item2, old_route);
                toStartFrom.RemoveRoute(new_route);

            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            if (!strategyHasExecuted)
                return toStartFrom;

            foreach (Order order in routeCreated.Orders)
                order.AddAvailableOrderBackToCluster();

            toStartFrom.RemoveRoute(routeCreated);
            routeCreated.Destroy();

            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            Planning = toStartFrom.GetRandomPlanning();
            if (Planning.Item3.Count == 0)
                return toStartFrom;

            int routeIndex = random.Next(Planning.Item3.Count);
            routeDeleted = Planning.Item3[routeIndex];

            toStartFrom.RemoveRouteFromPlanning(Planning.Item1, Planning.Item2, routeDeleted);

            strategyHasExecuted = true;
            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            if (!strategyHasExecuted)
                return toStartFrom;

            Route routeRestored = new Route(dayDestroyed);
            foreach (Order order in ordersDestroyed)
            {
                routeRestored.AddOrder(order);
                order.RemoveAvailableOrderFromCluster();
            }
            toStartFrom.AddRoute(routeRestored);

            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            if (toStartFrom.AvailableRoutes.Count == 0)
                return toStartFrom;

            int routeIndex = random.Next(toStartFrom.AvailableRoutes.Count);
            Route routeToDestroy = toStartFrom.AvailableRoutes[routeIndex];
            toStartFrom.RemoveRoute(routeToDestroy);
            ordersDestroyed = routeToDestroy.Orders;
            dayDestroyed = routeToDestroy.Day;
            routeToDestroy.Destroy();

            strategyHasExecuted = true;
            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            if (!strategyHasExecuted)
                return toStartFrom;

            for (int i = 0; i < 2; i++)
                originalRoutes[i].RemoveOrder(ordersSwapped[(i + 1) % 2]);

            for (int i = 0; i < 2; i++)
                if (ordersBehindOrderMarkedForSwap[i] == null)
                    originalRoutes[i].AddOrderAtStart(ordersSwapped[i]);
                else
                    originalRoutes[i].AddOrderAt(ordersSwapped[i], ordersBehindOrderMarkedForSwap[i]);

            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            if (!strategyHasExecuted)
                return toStartFrom;

            Route[] routesToSwap = new Route[2];
            for (int i = 0; i < 2; i++)
                routesToSwap[i] = Plans[i].Item3[routeIndicesSwapped[i]];

            for (int i = 0; i < 2; i++)
            {
                toStartFrom.RemoveRouteFromPlanning(Plans[i].Item1, Plans[i].Item2, routesToSwap[i]);
                toStartFrom.AddRouteToPlanning(Plans[(i + 1) % 2].Item1, Plans[(i + 1) % 2].Item2, routesToSwap[i]);
            }

            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            Planning = toStartFrom.GetRandomPlanning();
            if (Planning.Item3.Count == 0)
                return toStartFrom;

            Route routeToDestroy = Planning.Item3[random.Next(Planning.Item3.Count)];
            ordersDestroyed = routeToDestroy.Orders;
            dayDestroyed = routeToDestroy.Day;

            toStartFrom.RemoveRouteFromPlanning(Planning.Item1, Planning.Item2, routeToDestroy);
            toStartFrom.RemoveRoute(routeToDestroy);
            routeToDestroy.Destroy();

            strategyHasExecuted = true;
            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            Plans[0] = toStartFrom.GetRandomPlanning();
            Plans[1] = toStartFrom.GetRandomPlanning();

            if (Plans[0].Item3.Count == 0 || Plans[1].Item3.Count == 0 || Plans[0].Item1 != Plans[1].Item1 || (Plans[0].Equals(Plans[1]) && Plans[0].Item3.Count < 2))
                return toStartFrom;

            for (int i = 0; i < 2; i++)
            {
                originalRoutes[i] = Plans[i].Item3[random.Next(Plans[i].Item3.Count)];
                if (originalRoutes[i].Orders.Count < 2 || (i == 1 && originalRoutes[0].Equals(originalRoutes[1])))
                    return toStartFrom;

                int swapOrderIndex = random.Next(originalRoutes[i].Orders.Count - 1);
                ordersSwapped[i] = originalRoutes[i].Orders[swapOrderIndex];
                ordersBehindOrderMarkedForSwap[i] = swapOrderIndex == 0 ? null : originalRoutes[i].Orders[swapOrderIndex - 1];
            }

            for (int i = 0; i < 2; i++)
            {
                double timeLimit = 0.0d; // Check if route can be swapped traveltime-wise
                foreach (Route route in Plans[i].Item3)
                    if (route != originalRoutes[i])
                        timeLimit += route.TravelTime;

                timeLimit = 43200.0d - timeLimit;

                if (!originalRoutes[i].CanSwapOrderFromDifferentRoutes(ordersSwapped[(i + 1) % 2], ordersSwapped[i], timeLimit))
                    return toStartFrom; // if a route could not be swapped...
            }

            for (int i = 0; i < 2; i++)
                originalRoutes[i].RemoveOrder(ordersSwapped[i]);

            for (int i = 0; i < 2; i++)
                if (ordersBehindOrderMarkedForSwap[i] == null)
                    originalRoutes[i].AddOrderAtStart(ordersSwapped[(i + 1) % 2]);
                else
                    originalRoutes[i].AddOrderAt(ordersSwapped[(i + 1) % 2], ordersBehindOrderMarkedForSwap[i]);

            strategyHasExecuted = true;
            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            Plans[0] = toStartFrom.GetRandomPlanning();
            Plans[1] = toStartFrom.GetRandomPlanning();

            if (Plans[0].Item3.Count == 0 || Plans[1].Item3.Count == 0 || (Plans[0].Equals(Plans[1]) && Plans[0].Item3.Count < 2))
                return toStartFrom;

            for (int i = 0; i < 2; i++)
            {
                originalRoutes[i] = Plans[i].Item3[random.Next(Plans[i].Item3.Count)];
                if (originalRoutes[i].Orders.Count < 2 || (i == 1 && originalRoutes[0].Equals(originalRoutes[1])))
                    return toStartFrom;

                int shiftOrderIndex = random.Next(originalRoutes[i].Orders.Count - 1);
                ordersShifted[i] = originalRoutes[i].Orders[shiftOrderIndex];

                if (i == 0)
                    orderInFrontOfTheShiftedOrder = shiftOrderIndex == 0 ? null : originalRoutes[0].Orders[shiftOrderIndex - 1];
            }

            double timeLimit = 0.0d; // Check if route can be swapped traveltime-wise
            foreach (Route route in Plans[1].Item3)
                if (route != originalRoutes[1])
                    timeLimit += route.TravelTime;

            timeLimit = 43200.0d - timeLimit;

            if (originalRoutes[1].CanAddOrderAfter(ordersShifted[0], ordersShifted[1], timeLimit)) // Check if can be shifted
            {
                originalRoutes[0].RemoveOrder(ordersShifted[0]);
                originalRoutes[1].AddOrderAt(ordersShifted[0], ordersShifted[1]);
                strategyHasExecuted = true;

                if (originalRoutes[0].Orders.Count == 1) // if route has only 0order (because other order has been shifted away...)
                {
                    toStartFrom.RemoveRouteFromPlanning(Plans[0].Item1, Plans[0].Item2, originalRoutes[0]);
                    toStartFrom.RemoveRoute(originalRoutes[0]);
                }
            }

            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            if (!strategyHasExecuted)
                return toStartFrom;

            if (OriginalRoute.Orders.Count == 1)
            { // If empty
                toStartFrom.AddRoute(OriginalRoute);
                toStartFrom.AddRouteToPlanning(Planning.Item1, Planning.Item2, OriginalRoute);
            }

            OrderRemoved.RemoveAvailableOrderFromCluster();
            if (OrderBefore == null)
                OriginalRoute.AddOrderAtStart(OrderRemoved);
            else
                OriginalRoute.AddOrderAt(OrderRemoved, OrderBefore);

            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            if (!strategyHasExecuted)
                return toStartFrom;

            originalRoutes[1].RemoveOrder(ordersShifted[0]);

            if (originalRoutes[0].Orders.Count == 1) // if route has only 0order (because other order has been shifted away and the route has been deleted)
            {
                toStartFrom.AddRoute(originalRoutes[0]);
                toStartFrom.AddRouteToPlanning(Plans[0].Item1, Plans[0].Item2, originalRoutes[0]);
            }

            if (orderInFrontOfTheShiftedOrder != null)
                originalRoutes[0].AddOrderAt(ordersShifted[0], orderInFrontOfTheShiftedOrder);
            else
                originalRoutes[0].AddOrderAtStart(ordersShifted[0]);

            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            if (toStartFrom.AvailableRoutes.Count == 0)
                return toStartFrom; // No routes to plan

            Planning = toStartFrom.GetRandomPlanning();
            routePlanned = toStartFrom.AvailableRoutes[random.Next(toStartFrom.AvailableRoutes.Count)];

            double totalTravelTime = 0.0d;
            foreach (Route route in Planning.Item3)
                totalTravelTime += route.TravelTime;

            if (routePlanned.Day != Planning.Item1 || totalTravelTime + routePlanned.TravelTime > 43200.0d)
                return toStartFrom;

            toStartFrom.AddRouteToPlanning(Planning.Item1, Planning.Item2, routePlanned);
            strategyHasExecuted = true;

            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            Planning = toStartFrom.GetRandomPlanning();
            if (Planning.Item3.Count == 0)
                return toStartFrom;

            old_route = Planning.Item3[random.Next(Planning.Item3.Count)];
            if (old_route == null || old_route.Orders.Count < 4)
                return toStartFrom; // Could not find a valid route to shuffle

            new_route = new Route(Planning.Item1);
            foreach (Order order in old_route.Orders)
                new_route.AddOrder(order);

            int firstIndex = random.Next(old_route.Orders.Count - 1);
            int secondIndex = random.Next(old_route.Orders.Count - 1);
            int thirdIndex = random.Next(old_route.Orders.Count - 1);

            while (firstIndex == secondIndex || firstIndex == thirdIndex || secondIndex == thirdIndex)
                return toStartFrom;

            double timeLimit = 0.0d; // Check if route can be swapped traveltime-wise
            foreach (Route route in Planning.Item3)
                if (route != old_route)
                    timeLimit += route.TravelTime;

            timeLimit = 43200.0d - timeLimit;

            if (new_route.CanHalfSwapOrder(old_route.Orders[firstIndex], old_route.Orders[thirdIndex], old_route.Orders[thirdIndex], timeLimit))
            {
                new_route.HalfSwapOrders(old_route.Orders[firstIndex], old_route.Orders[thirdIndex], old_route.Orders[thirdIndex]);
                toStartFrom.AddRoute(new_route);
                toStartFrom.RemoveRouteFromPlanning(Planning.Item1, Planning.Item2, old_route);
                toStartFrom.AddRouteToPlanning(Planning.Item1, Planning.Item2, new_route);
                toStartFrom.RemoveRoute(old_route);

                strategyHasExecuted = true;
            }

            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            for (int i = 0; i < 2; i++)
            {
                Plans[i] = toStartFrom.GetRandomPlanning();
                if (Plans[i].Item3.Count == 0 || (i == 1 && Plans[0].Item1 != Plans[1].Item1)) // Make sure it has routes to swap and is on the same day
                    return toStartFrom;

                routeIndicesSwapped[i] = random.Next(Plans[i].Item3.Count);
                if (i == 1 && routeIndicesSwapped[0] == routeIndicesSwapped[1])
                    return toStartFrom;
            }

            Route[] routesToSwap = new Route[2];
            for (int i = 0; i < 2; i++)
                routesToSwap[i] = Plans[i].Item3[routeIndicesSwapped[i]];

            for (int i = 0; i < 2; i++) // Check if route can be swapped traveltime-wise
            {
                double tempTT = 0.0d;
                foreach (Route route in Plans[i].Item3)
                    if(route != routesToSwap[i])
                        tempTT += route.TravelTime;

                tempTT += routesToSwap[(i + 1) % 2].TravelTime;

                if (tempTT > 43200.0d)
                    return toStartFrom;
            }

            for (int i = 0; i < 2; i++)
            {
                toStartFrom.RemoveRouteFromPlanning(Plans[i].Item1, Plans[i].Item2, routesToSwap[i]);
                toStartFrom.AddRouteToPlanning(Plans[(i + 1) % 2].Item1, Plans[(i + 1) % 2].Item2, routesToSwap[i]);
            }

            strategyHasExecuted = true;
            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            // Revert abomination to Patient Zero...
            toStartFrom.RemoveRouteFromPlanning(planningForSelectedRoute.Item1, planningForSelectedRoute.Item2, bestAbominationOffspringRoute);
            toStartFrom.AddRouteToPlanning(planningForSelectedRoute.Item1, planningForSelectedRoute.Item2, originalRoute);

            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            planningForSelectedRoute = toStartFrom.GetRandomPlanning();
            originalRoute = planningForSelectedRoute.Item3[random.Next(planningForSelectedRoute.Item3.Count)];
            double originalTravelTime = originalRoute.TravelTime;
            int numOfSlices = random.Next(1, originalRoute.Orders.Count - 2);

            List<int> sliceIndices = new List<int>();
            for (int i = 1; i < numOfSlices; i++)
            {
                bool hasAddedAnIndex = false;
                do
                {
                    int sliceIndex = random.Next(1, numOfSlices);
                    if (!sliceIndices.Contains(sliceIndex))
                    {
                        sliceIndices.Add(sliceIndex);
                        hasAddedAnIndex = true;
                    }
                } while (!hasAddedAnIndex);
            }
            sliceIndices.Sort();

            // COMMENCE THE GENETIC EXPERIMENTS!
            // OPERATION SLICE & SPLICE AN ABOMINATION IS ACTIVE!

            List<Order>[] orderSlices = new List<Order>[sliceIndices.Count];
            for (int i = 0; i < sliceIndices.Count; i++)
            {
                orderSlices[i] = new List<Order>();
                int startIndex = i == 0 ? 0 : sliceIndices[i - 1];

                for (int j = startIndex; j < sliceIndices[i]; j++)
                    orderSlices[i].Add(originalRoute.Orders[j]);
            }

            // Now that you've sliced up the orders in the selected route, it is time for randomizing the slices and putting it back together

            Route firstAbominationRoute = new Route(originalRoute.Day);
            List<int> slicesIndexPutBack = new List<int>();
            for (int i = 0; i < orderSlices.Length - 2; i++)
            {
                bool hasPutBackASlice = false;
                do
                {
                    int sliceIndex = random.Next(1, orderSlices.Length - 1);
                    if (!slicesIndexPutBack.Contains(sliceIndex))
                    {
                        for (int j = 0; j < orderSlices[sliceIndex].Count; j++)
                            if (orderSlices[sliceIndex][j].OrderNumber != 0)
                                firstAbominationRoute.AddOrder(orderSlices[sliceIndex][j]);

                        slicesIndexPutBack.Add(sliceIndex);
                        hasPutBackASlice = true;
                    }
                } while (!hasPutBackASlice);
            }

            // COMMENCE THE GENETIC EXPERIMENTS PHASE TWO!
            // OPERATION DARWIN'S ABOMINATION REPRODUCTION IS NOW OPERATIONAL!

            Route bestBoyAbominationOffspring = originalRoute;
            Route bestGirlAbominationOffspring = firstAbominationRoute;
            Boolean boyAbominationIsTheBest = bestBoyAbominationOffspring.TravelTime >= bestGirlAbominationOffspring.TravelTime;
            int numberOfGenesThatAreTransferred = originalRoute.Orders.Count / 2;
            List<Order> ordersSelectedForGeneticSwap = new List<Order>();

            for (int numOfGenerationsToMake = 64; numOfGenerationsToMake > 0; numOfGenerationsToMake--)
            {
                ordersSelectedForGeneticSwap.Clear();

                int orderIndex = -1;
                do
                {
                    orderIndex = random.Next(orderSlices.Length - 1); // What?
                    Order randomOrder = null;

                    if (boyAbominationIsTheBest)
                        randomOrder = bestBoyAbominationOffspring.Orders[orderIndex];
                    else
                        randomOrder = bestGirlAbominationOffspring.Orders[orderIndex];

                    if (ordersSelectedForGeneticSwap.Contains(randomOrder))
                        continue;

                    ordersSelectedForGeneticSwap.Add(randomOrder);

                } while (ordersSelectedForGeneticSwap.Count * 2 < numberOfGenesThatAreTransferred - 1);

                List<int> indicesToBeSwaped = new List<int>(); // Change into a array [2], to keep track which index belongs where
                foreach (Order order in ordersSelectedForGeneticSwap)
                {
                    indicesToBeSwaped.Add(bestBoyAbominationOffspring.Orders.FindIndex(o => o == order));
                    indicesToBeSwaped.Add(bestGirlAbominationOffspring.Orders.FindIndex(o => o == order));
                }
                indicesToBeSwaped.Sort();

                Route newBoyAbominationOffspring = new Route(originalRoute.Day);
                Route newGirlAbominationOffspring = new Route(originalRoute.Day);

                for (int index = 0; index < originalRoute.Orders.Count - 1; index++)
                {
                    if (indicesToBeSwaped.Contains(index)) // Erm.. What?
                    {
                        newBoyAbominationOffspring.AddOrder(bestGirlAbominationOffspring.Orders[index]);
                        newGirlAbominationOffspring.AddOrder(bestBoyAbominationOffspring.Orders[index]);
                    }
                    else
                    {
                        newBoyAbominationOffspring.AddOrder(bestBoyAbominationOffspring.Orders[index]);
                        newGirlAbominationOffspring.AddOrder(bestGirlAbominationOffspring.Orders[index]);
                    }
                }

                if (newBoyAbominationOffspring.isValid() && !newGirlAbominationOffspring.isValid()) // One is allowed
                    if (bestBoyAbominationOffspring.TravelTime < bestGirlAbominationOffspring.TravelTime)
                        bestGirlAbominationOffspring = newBoyAbominationOffspring;
                    else
                        bestBoyAbominationOffspring = newBoyAbominationOffspring;
                else if (!newBoyAbominationOffspring.isValid() && newGirlAbominationOffspring.isValid()) // Other one allowed
                    if (bestBoyAbominationOffspring.TravelTime < bestGirlAbominationOffspring.TravelTime)
                        bestGirlAbominationOffspring = newGirlAbominationOffspring;
                    else
                        bestBoyAbominationOffspring = newGirlAbominationOffspring;
                else if (!newBoyAbominationOffspring.isValid() && !newGirlAbominationOffspring.isValid()) // Neither is allowed
                {
                    numOfGenerationsToMake--;
                    continue;
                }

                bool newGirlAbominationOffspringIstheBest = newBoyAbominationOffspring.TravelTime <= newGirlAbominationOffspring.TravelTime;
                if (boyAbominationIsTheBest)
                {
                    if (newGirlAbominationOffspringIstheBest)
                    {
                        if (bestGirlAbominationOffspring.TravelTime < newGirlAbominationOffspring.TravelTime)
                        {
                            bestGirlAbominationOffspring = newGirlAbominationOffspring;

                            if (bestBoyAbominationOffspring.TravelTime < newBoyAbominationOffspring.TravelTime)
                            {
                                bestBoyAbominationOffspring = newBoyAbominationOffspring;
                            }
                        }
                    }
                    else
                    {
                        if (bestGirlAbominationOffspring.TravelTime < newBoyAbominationOffspring.TravelTime)
                        {
                            bestGirlAbominationOffspring = newBoyAbominationOffspring;

                            if (bestBoyAbominationOffspring.TravelTime < newGirlAbominationOffspring.TravelTime)
                            {
                                bestBoyAbominationOffspring = newGirlAbominationOffspring;
                            }
                        }
                    }
                }
                else
                {
                    if (newGirlAbominationOffspringIstheBest)
                    {
                        if (bestBoyAbominationOffspring.TravelTime < newGirlAbominationOffspring.TravelTime)
                        {
                            bestBoyAbominationOffspring = newGirlAbominationOffspring;

                            if (bestGirlAbominationOffspring.TravelTime < newBoyAbominationOffspring.TravelTime)
                            {
                                bestGirlAbominationOffspring = newBoyAbominationOffspring;
                            }
                        }
                    }
                    else
                    {
                        if (bestBoyAbominationOffspring.TravelTime < newBoyAbominationOffspring.TravelTime)
                        {
                            bestBoyAbominationOffspring = newBoyAbominationOffspring;

                            if (bestGirlAbominationOffspring.TravelTime < newGirlAbominationOffspring.TravelTime)
                            {
                                bestGirlAbominationOffspring = newGirlAbominationOffspring;
                            }
                        }
                    }
                }

                boyAbominationIsTheBest = bestBoyAbominationOffspring.TravelTime >= bestGirlAbominationOffspring.TravelTime;
                numOfGenerationsToMake--;
            }

            // PHASE 3 - INSERT THE ABOMINATION INTO THE PUBLIC!

            bestAbominationOffspringRoute = boyAbominationIsTheBest ? bestBoyAbominationOffspring : bestGirlAbominationOffspring;

            Console.WriteLine("Original Travel Time:                     {0}", originalTravelTime); // These three lines are temporarily here
            Console.WriteLine("The First Abomination Travel Time:        {0}", firstAbominationRoute.TravelTime);
            Console.WriteLine("Best Abomination Offspring Travel Time:   {0}", bestAbominationOffspringRoute.TravelTime);

            toStartFrom.RemoveRouteFromPlanning(planningForSelectedRoute.Item1, planningForSelectedRoute.Item2, originalRoute);
            toStartFrom.AddRouteToPlanning(planningForSelectedRoute.Item1, planningForSelectedRoute.Item2, bestAbominationOffspringRoute);

            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            planningForSelectedRoute = toStartFrom.GetRandomPlanning();
            firstOriginalRoute = planningForSelectedRoute.Item3[random.Next(planningForSelectedRoute.Item3.Count)];
            secondOriginalRoute = planningForSelectedRoute.Item3[random.Next(planningForSelectedRoute.Item3.Count)];

            for (int index = 0; index < 5 && firstOriginalRoute != secondOriginalRoute; index++)
                secondOriginalRoute = planningForSelectedRoute.Item3[random.Next(planningForSelectedRoute.Item3.Count)];

            double firstOriginalTravelTime = firstOriginalRoute.TravelTime;
            double secondOriginalTravelTime = secondOriginalRoute.TravelTime;
            int[] numOfSlices = new int[2] {random.Next(1, firstOriginalRoute.Orders.Count - 2), random.Next(1, secondOriginalRoute.Orders.Count - 2)};
            List<int>[] sliceIndices = new List<int>[2];

            for (int i = 0; i < sliceIndices.Length; i++)
            {
                sliceIndices[i] = new List<int>();
                for (int j = 0; j < numOfSlices[i]; j++)
                {
                    bool hasAddedAnIndex = false;
                    do
                    {
                        int sliceIndex = random.Next(1, numOfSlices[i]);
                        if (!sliceIndices[i].Contains(sliceIndex))
                        {
                            sliceIndices[i].Add(sliceIndex);
                            hasAddedAnIndex = true;
                        }
                    } while (!hasAddedAnIndex);
                }

                sliceIndices[i].Sort();
            }

            // COMMENCE THE GENETIC EXPERIMENTS!
            // OPERATION SLICE & SPLICE AN ABOMINATION IS ACTIVE!

            List<Order>[][] orderSlices = new List<Order>[sliceIndices.Length][];
            for (int index = 0; index < sliceIndices.Length; index++)
            {
                orderSlices[index] = new List<Order>[sliceIndices[index].Count];
                for (int i = 0; i < sliceIndices[index].Count; i++)
                {
                    orderSlices[index][i] = new List<Order>();
                    int startIndex = i == 0 ? 0 : sliceIndices[index][i - 1];

                    for (int j = startIndex; j < sliceIndices[index][i]; j++)
                        if(index == 0)
                            orderSlices[0][i].Add(firstOriginalRoute.Orders[j]);
                        else
                            orderSlices[1][i].Add(secondOriginalRoute.Orders[j]);
                }
            }

            // Now that you've sliced up the orders in the selected route, it is time for randomizing the slices and putting it back together

            firstAbominationRoute = new Route(planningForSelectedRoute.Item1);
            secondAbominationRoute = new Route(planningForSelectedRoute.Item1);
            List<int>[] slicesIndexPutBack = new List<int>[2];
            for (int index = 0; index < sliceIndices.Length; index++)
            {
                slicesIndexPutBack[index] = new List<int>();
                for (int i = 0; i < orderSlices[index].Length - 2; i++)
                {
                    bool hasPutBackASlice = false;
                    do
                    {
                        int sliceIndex = random.Next(1, orderSlices[index].Length - 1);
                        if (!slicesIndexPutBack[index].Contains(sliceIndex))
                        {
                            for (int j = 0; j < orderSlices[index][sliceIndex].Count; j++)
                                if (orderSlices[index][sliceIndex][j].OrderNumber != 0)

                                    if (index == 0)
                                        firstAbominationRoute.AddOrder(orderSlices[index][sliceIndex][j]);
                                    else
                                        secondAbominationRoute.AddOrder(orderSlices[index][sliceIndex][j]);

                            slicesIndexPutBack[index].Add(sliceIndex);
                            hasPutBackASlice = true;
                        }
                    } while (!hasPutBackASlice);
                }
            }

            // COMMENCE THE GENETIC EXPERIMENTS PHASE TWO!
            // OPERATION DARWIN'S ABOMINATION REPRODUCTION IS NOW OPERATIONAL!

            int numOfGenerationsToMake = 64;
            Route bestBoyAbominationOffspring = firstAbominationRoute;
            Route bestGirlAbominationOffspring = secondAbominationRoute;
            int[] numberOfGenesThatAreTransferred = new int[2] { random.Next(firstAbominationRoute.Orders.Count / 4, // 25%
                                                                    firstAbominationRoute.Orders.Count / 2), // 50%
                                                                random.Next(secondAbominationRoute.Orders.Count / 4, // 25%
                                                                    secondAbominationRoute.Orders.Count / 2)}; // 50%

            List<Order>[] ordersSelectedForGeneticSwap = new List<Order>[2] { new List<Order>(), new List<Order>() };

            while (numOfGenerationsToMake > 0)
            {
                for (int i = 0; i < 2; i++)
                {
                    ordersSelectedForGeneticSwap[i].Clear();

                    int orderIndex = -1;
                    do
                    {
                        orderIndex = random.Next(orderSlices[i].Length - 1);
                        Order randomOrder = null;

                        if (i == 0)
                            randomOrder = bestBoyAbominationOffspring.Orders[orderIndex];
                        else
                            randomOrder = bestGirlAbominationOffspring.Orders[orderIndex];

                        if (ordersSelectedForGeneticSwap[i].Contains(randomOrder))
                            continue;

                        ordersSelectedForGeneticSwap[i].Add(randomOrder);

                    } while (ordersSelectedForGeneticSwap[i].Count * 2 < numberOfGenesThatAreTransferred[i] - 1);

                    List<int> indicesToBeSwaped = new List<int>(); // FIX MEE
                    foreach (Order order in ordersSelectedForGeneticSwap[i]) // TODO, not (exclusive) simularities, but just 'random' orders
                    {
                        indicesToBeSwaped.Add(bestBoyAbominationOffspring.Orders.FindIndex(o => o == order));
                        indicesToBeSwaped.Add(bestGirlAbominationOffspring.Orders.FindIndex(o => o == order));
                    }
                    indicesToBeSwaped.Sort();

                Route newBoyAbominationOffspring = new Route(planningForSelectedRoute.Item1);
                Route newGirlAbominationOffspring = new Route(planningForSelectedRoute.Item1);

                for (int index = 0; index < firstOriginalRoute.Orders.Count - 1; index++) // FIX MEE TOOO!!
                {
                    if (indicesToBeSwaped.Contains(index))
                    {
                        newBoyAbominationOffspring.AddOrder(bestGirlAbominationOffspring.Orders[index]);
                        newGirlAbominationOffspring.AddOrder(bestBoyAbominationOffspring.Orders[index]);
                    }
                    else
                    {
                        newBoyAbominationOffspring.AddOrder(bestBoyAbominationOffspring.Orders[index]);
                        newGirlAbominationOffspring.AddOrder(bestGirlAbominationOffspring.Orders[index]);
                    }
                }

                Boolean newGirlAbominationOffspringIstheBest = newBoyAbominationOffspring.TravelTime <= newGirlAbominationOffspring.TravelTime;
                if (true) // if (boyAbominationIsTheBest) Find alternative!
                {
                    if (newGirlAbominationOffspringIstheBest)
                    {
                        if (bestGirlAbominationOffspring.TravelTime < newGirlAbominationOffspring.TravelTime)
                        {
                            bestGirlAbominationOffspring = newGirlAbominationOffspring;

                            if (bestBoyAbominationOffspring.TravelTime < newBoyAbominationOffspring.TravelTime)
                            {
                                bestBoyAbominationOffspring = newBoyAbominationOffspring;
                            }
                        }
                    }
                    else
                    {
                        if (bestGirlAbominationOffspring.TravelTime < newBoyAbominationOffspring.TravelTime)
                        {
                            bestGirlAbominationOffspring = newBoyAbominationOffspring;

                            if (bestBoyAbominationOffspring.TravelTime < newGirlAbominationOffspring.TravelTime)
                            {
                                bestBoyAbominationOffspring = newGirlAbominationOffspring;
                            }
                        }
                    }
                }
                else
                {
                    if (newGirlAbominationOffspringIstheBest)
                    {
                        if (bestBoyAbominationOffspring.TravelTime < newGirlAbominationOffspring.TravelTime)
                        {
                            bestBoyAbominationOffspring = newGirlAbominationOffspring;

                            if (bestGirlAbominationOffspring.TravelTime < newBoyAbominationOffspring.TravelTime)
                            {
                                bestGirlAbominationOffspring = newBoyAbominationOffspring;
                            }
                        }
                    }
                    else
                    {
                        if (bestBoyAbominationOffspring.TravelTime < newBoyAbominationOffspring.TravelTime)
                        {
                            bestBoyAbominationOffspring = newBoyAbominationOffspring;

                            if (bestGirlAbominationOffspring.TravelTime < newGirlAbominationOffspring.TravelTime)
                            {
                                bestGirlAbominationOffspring = newGirlAbominationOffspring;
                            }
                        }
                    }
                }
                }

                numOfGenerationsToMake--;
            }

            // PHASE 3 - INSERT THE ABOMINATION INTO THE PUBLIC!

            firstBestAbominationOffspringRoute = bestBoyAbominationOffspring;
            secondBestAbominationOffspringRoute = bestGirlAbominationOffspring;
            // secondBest?

            Console.WriteLine("First Route: Original Travel Time:                     {0}", firstOriginalTravelTime); // NEEDS FIXING
            Console.WriteLine("First Route: The First Abomination Travel Time:        {0}", firstAbominationRoute.TravelTime); // NEEDS FIXING
            Console.WriteLine("First Route: Best Abomination Offspring Travel Time:   {0}", firstBestAbominationOffspringRoute.TravelTime); // NEEDS FIXING

            Console.WriteLine("Second Route: Original Travel Time:                     {0}", secondOriginalTravelTime); // NEEDS FIXING
            Console.WriteLine("Second Route: The First Abomination Travel Time:        {0}", secondAbominationRoute.TravelTime); // NEEDS FIXING
            Console.WriteLine("Second Route: Best Abomination Offspring Travel Time:   {0}", secondBestAbominationOffspringRoute.TravelTime); // NEEDS FIXING

            planningForSelectedRoute.Item3.Remove(firstOriginalRoute); // NEEDS FIXING?
            planningForSelectedRoute.Item3.Add(firstBestAbominationOffspringRoute); // NEEDS FIXING?
            planningForSelectedRoute.Item3.Remove(secondOriginalRoute); // NEEDS FIXING?
            planningForSelectedRoute.Item3.Add(secondBestAbominationOffspringRoute); // NEEDS FIXING?

            toStartFrom.RemoveItemFromPlanning(planningForSelectedRoute.Item1, planningForSelectedRoute.Item2); // NEEDS FIXING
            toStartFrom.AddNewItemToPlanning(planningForSelectedRoute.Item1, planningForSelectedRoute.Item2, planningForSelectedRoute.Item3); // NEEDS FIXING

            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            // Revert abomination to Patient Zero...
            planningForSelectedRoute.Item3.Remove(firstBestAbominationOffspringRoute); // NEEDS FIXING
            planningForSelectedRoute.Item3.Add(firstOriginalRoute); // NEEDS FIXING

            toStartFrom.RemoveItemFromPlanning(planningForSelectedRoute.Item1, planningForSelectedRoute.Item2); // NEEDS FIXING
            toStartFrom.AddNewItemToPlanning(planningForSelectedRoute.Item1, planningForSelectedRoute.Item2, planningForSelectedRoute.Item3); // NEEDS FIXING

            return toStartFrom;
        }
        public override Solution undoStrategy(Solution toStartFrom)
        {
            // Nette manier zou zijn om de tuple weer op te halen gebaseerd op Planning.Item2 en dag.
            RoutesFromSolution.Remove(new_route);
            RoutesFromSolution.Add(old_route);

            toStartFrom.RemoveItemFromPlanning(Planning.Item1, Planning.Item2);
            toStartFrom.AddNewItemToPlanning(Planning.Item1, Planning.Item2, RoutesFromSolution);

            return toStartFrom;
        }
        public override Solution executeStrategy(Solution toStartFrom)
        {
            Planning = toStartFrom.GetRandomPlanning();
            RoutesFromSolution = Planning.Item3;

            //save the begin route for rollback
            old_route = RoutesFromSolution[random.Next(RoutesFromSolution.Count)];

            //copy the begin route for the 2-opt and create the route for the 2-opt check
            for (int i = 0; i < routesToWorkWith.Length; i++)
                routesToWorkWith[i] = new Route(Planning.Item1);

            new_route = new Route(Planning.Item1);
            foreach (Order order in old_route.Orders)
            {
                for (int i = 0; i < routesToWorkWith.Length; i++)
                    routesToWorkWith[i].AddOrder(order);

                new_route.AddOrder(order);
            }

            //start doing the opt-3 algorithm on the route list
            double best_traveltime = old_route.TravelTime;
            double[] new_traveltime = new double[NumberOfRoutesCreated];
            for (int i = 0; i < new_traveltime.Length; i++)
                new_traveltime[i] = double.MaxValue;

            int improvestep = 0;
            while (improvestep < 10)
            {
                for (int i = 0; i < old_route.Orders.Count - 3; i++)
                {
                    for (int j = i + 1; j < old_route.Orders.Count - 2; j++)
                    {
                        for (int k = j + 1; k < old_route.Orders.Count - 1; k++)
                        {
                            //swap the 2 coords
                            Order[] initialRouteI = new Order[NumberOfRoutesCreated];
                            for (int index = 0; index < initialRouteI.Length; index++)
                                initialRouteI[index] = routesToWorkWith[index].Orders[i];

                            Order[] initialRouteJ = new Order[NumberOfRoutesCreated];
                            for (int index = 0; index < initialRouteJ.Length; index++)
                                initialRouteJ[index] = routesToWorkWith[index].Orders[j];

                            Order[] initialRouteK = new Order[NumberOfRoutesCreated];
                            for (int index = 0; index < initialRouteK.Length; index++)
                                initialRouteK[index] = routesToWorkWith[index].Orders[k];

                            for (int index = 0; index < routesToWorkWith.Length; index++)
                            {
                                swapOrders(initialRouteI[index], initialRouteK[index], routesToWorkWith[index]);
                                swapOrders(initialRouteI[index], initialRouteJ[index], routesToWorkWith[index]);
                                new_traveltime[index] = routesToWorkWith[index].TravelTime;
                            }

                            bool hasABetterTime = false;
                            for (int index = 0; index < new_traveltime.Length; index++)
                            {
                                if (new_traveltime[index] < best_traveltime)
                                {
                                    improvestep = 0;
                                    hasABetterTime = true;

                                    new_route = routesToWorkWith[index];
                                    best_traveltime = new_traveltime[index];
                                }
                            }

                            if (hasABetterTime)
                            {
                                for (int index = 0; index < routesToWorkWith.Length; index++)
                                    routesToWorkWith[index] = new Route(Planning.Item1);

                                foreach (Order order in old_route.Orders)
                                    for (int index = 0; index < routesToWorkWith.Length; index++)
                                        routesToWorkWith[index].AddOrder(order);

                            }
                        }
                    }
                }

                improvestep++;
            }

            RoutesFromSolution.Remove(old_route);
            RoutesFromSolution.Add(new_route);

            toStartFrom.RemoveItemFromPlanning(Planning.Item1, Planning.Item2);
            toStartFrom.AddNewItemToPlanning(Planning.Item1, Planning.Item2, RoutesFromSolution);

            return toStartFrom;
        }