public void ArrangedCorrectly(int numberOfTests)
        {
            Route route = new Route();

            Random         randomGenerator = new Random();
            List <Segment> segmentsList    = new List <Segment>(LondonSegments_Arrangeable);

            for (int testsCounter = 0; testsCounter < numberOfTests; testsCounter++)
            {
                // Shuffle the list (Fisher-Yates algorithm)
                // https://stackoverflow.com/questions/273313/randomize-a-listt
                for (int i = segmentsList.Count - 1; i > 1; i--)
                {
                    int k     = randomGenerator.Next(i + 1);
                    var value = segmentsList[k];
                    segmentsList[k] = segmentsList[i];
                    segmentsList[i] = value;
                }
                //Console.WriteLine(segmentsList[3]);  // to be sure that the list is really has been shuffled
                HashSet <Segment> segmentsSet = new HashSet <Segment>(segmentsList);

                route.AcceptSegments(segmentsSet);
                route.Arrange();
                LinkedList <Segment> output = new LinkedList <Segment>();
                foreach (Segment segment in route)
                {
                    output.AddLast(new Segment(segment));
                }

                Assert.True(Enumerable.SequenceEqual(LondonRoute_Arranged, output));

                route.Reset();
            }
        }
        public void GotExpected_DisruptedRouteException()
        {
            Route route = new Route();

            route.AcceptSegments(LondonSegments_NonArrangeable_Disrupted);

            var exception = Assert.Throws <DisruptedRouteException>(() => { route.Arrange(); });

            Assert.NotNull(exception);
        }
        public void GetRouteAsPointsCorrectly()
        {
            Route route = new Route();

            route.AcceptSegments(LondonSegments_Arrangeable);
            route.Arrange();

            IEnumerator <Point> outputEnumerator  = route.GetRouteAsPoints().GetEnumerator();
            IEnumerator <Point> correctEnumerator = LondonRouteAsPoints_Correct.GetEnumerator();

            while (correctEnumerator.MoveNext())
            {
                Assert.True(outputEnumerator.MoveNext(), "Correct output isn't over but the tested Route is over");
                Assert.Equal(correctEnumerator.Current, outputEnumerator.Current);
            }
            Assert.False(outputEnumerator.MoveNext(), "Correct output is over but the tested Route still producing values");
        }
        public void ReversedCorrectly()
        {
            Route route = new Route();

            route.AcceptSegments(LondonSegments_Arrangeable);
            route.Arrange();
            route.Reverse();

            LinkedList <Segment> output = new LinkedList <Segment>();

            foreach (Segment segment in route)
            {
                output.AddLast(new Segment(segment));
            }

            Assert.True(Enumerable.SequenceEqual(LondonRoute_ArrangedReversed, output), $"{output}");
        }
        static void Main(string[] args)
        {
            // Use a logging library to easily manage a program output for different configurations
            var nlogconfig = new NLog.Config.LoggingConfiguration();
            var logconsole = new NLog.Targets.ConsoleTarget("logconsole");

            nlogconfig.AddRule(LogLevel.Trace, LogLevel.Fatal, logconsole);
            LogManager.Configuration = nlogconfig;
            logger = LogManager.GetCurrentClassLogger();

            string[][] LondonAreas =
            {
                new string[] { "Теддингтон",       "Ноттинг-Хилл"     },
                new string[] { "Сити",             "Вестминстер"      },
                new string[] { "Ноттинг-Хилл",     "Южный Кенсингтон" },
                new string[] { "Детфорд",          "Фулем"            },
                new string[] { "Гринвич",          "Сербитон"         },
                new string[] { "Челси",            "Блумсбери"        },
                new string[] { "Южный Кенсингтон", "Челси"            },
                new string[] { "Сербитон",         "Детфорд"          },
                new string[] { "Вестминстер",      "Теддингтон"       },
                new string[] { "Блумсбери",        "Гринвич"          }
            };
            byte[][][] TokyoWards =
            {
                new byte[][] { Encoding.UTF8.GetBytes("Минато"),   Encoding.UTF8.GetBytes("Эдогава")  },
                new byte[][] { Encoding.UTF8.GetBytes("Тюо"),      Encoding.UTF8.GetBytes("Нэрима")   },
                new byte[][] { Encoding.UTF8.GetBytes("Ота"),      Encoding.UTF8.GetBytes("Синдзюку") },
                new byte[][] { Encoding.UTF8.GetBytes("Эдогава"),  Encoding.UTF8.GetBytes("Ота")      },
                new byte[][] { Encoding.UTF8.GetBytes("Сибуя"),    Encoding.UTF8.GetBytes("Итабаси")  },
                new byte[][] { Encoding.UTF8.GetBytes("Синдзюку"), Encoding.UTF8.GetBytes("Тосима")   },
                new byte[][] { Encoding.UTF8.GetBytes("Нэрима"),   Encoding.UTF8.GetBytes("Минато")   },
                new byte[][] { Encoding.UTF8.GetBytes("Бункё"),    Encoding.UTF8.GetBytes("Тюо")      },
                new byte[][] { Encoding.UTF8.GetBytes("Тосима"),   Encoding.UTF8.GetBytes("Кото")     },
                new byte[][] { Encoding.UTF8.GetBytes("Итабаси"),  Encoding.UTF8.GetBytes("Бункё")    }
            };

            HashSet <Segment> inputData;


            // =============== London ===============
            Route route = new Route("Лондон");

            try
            {
                inputData = Util.ConvertData(LondonAreas);
                logger.Info($"Data {LondonAreas.GetType()} {nameof(LondonAreas)} is converted");
                route.AcceptSegments(inputData);
            }
            catch (Exception ex)
            {
                logger.Error($"Cannot feed input {LondonAreas.GetType()} {nameof(LondonAreas)}: {ex}");
                return;
            }
            try
            {
                route.Arrange();
                logger.Info($"Segments {LondonAreas.GetType()} {nameof(LondonAreas)} were arranged successfully");
            }
            catch (Exception ex)
            {
                logger.Error($"Cannot arrange {LondonAreas.GetType()} {nameof(LondonAreas)}: {ex}");
                return;
            }
            Console.WriteLine(route);
            route.Reset();


            // =============== Tokyo ===============
            route.Name = "Токио";
            try
            {
                inputData = Util.ConvertData(TokyoWards);
                logger.Info($"Data {TokyoWards.GetType()} {nameof(TokyoWards)} is accepted");
                route.AcceptSegments(inputData);
            }
            catch (Exception ex)
            {
                logger.Error($"Cannot feed input {TokyoWards.GetType()} {nameof(TokyoWards)}: {ex}");
                return;
            }
            try
            {
                route.Arrange();
                logger.Info($"Segments {TokyoWards.GetType()} {nameof(TokyoWards)} were arranged successfully");
            }
            catch (Exception ex)
            {
                logger.Error($"Cannot arrange {TokyoWards.GetType()} {nameof(TokyoWards)}: {ex}");
                return;
            }
            Console.WriteLine(route);


            Console.WriteLine("Let's reverse the route:");
            route.Reverse();
            Console.WriteLine(route);


            Console.WriteLine("You can use Enumerator to fetch the segments one by one continuously:");
            IEnumerator <Segment> routeEnumerator = route.GetEnumerator();

            routeEnumerator.MoveNext();
            Console.WriteLine(routeEnumerator.Current);
            routeEnumerator.MoveNext();
            Console.WriteLine(routeEnumerator.Current);
            routeEnumerator.MoveNext();
            Console.WriteLine(routeEnumerator.Current);
            Console.WriteLine("...");
            Console.WriteLine("or to extract the resulted route as a whole in a loop\n");


            Console.WriteLine("Query public properties to get some status information:");
            Console.WriteLine($"DataAccepted: {route.DataAccepted}");
            Console.WriteLine($"Arranged: {route.Arranged}\n");

            Console.WriteLine("If you want to get the next point itself and not the segment use GetRouteAsPoints() method:");
            foreach (Point point in route.GetRouteAsPoints())
            {
                Console.Write($"{point} → ");
            }
            Console.WriteLine("\b\b ");
        }