/// <summary>
        /// Generates a route between a source and destination.
        /// </summary>
        /// <param name="source">
        /// The source node.
        /// </param>
        /// <param name="destination">
        /// The destination node.
        /// </param>
        /// <returns>
        /// A route between the origin and destination.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Thrown if the <see cref="searchType"/> field is invalid.
        /// </exception>
        public Route Generate(INetworkNode source, INetworkNode destination)
        {
            this.searchType = this.properties.SearchType;
            if (source.Id == -1)
            {
                source = this.properties.NetworkDataProviders[0].GetNodeClosestToPointWithinArea(
                    source, source, 1.0, true);
            }

            if (destination.Id == -1)
            {
                destination = this.properties.NetworkDataProviders[0].GetNodeClosestToPointWithinArea(
                    destination, destination, 1.0, true);
            }

            PTDepthFirstSearch searchAlgorithm;

            switch (this.searchType)
            {
                case SearchType.DFS_Standard:
                    searchAlgorithm = new PTDepthFirstSearch(
                        false, this.properties.NetworkDataProviders[0], source, destination);
                    break;
                case SearchType.DFS_BiDir:
                    searchAlgorithm = new PTDepthFirstSearch(
                        true, this.properties.NetworkDataProviders[0], source, destination);
                    break;
                case SearchType.Greedy_Standard:
                    searchAlgorithm = new PTGreedySearch(
                        false, this.properties.NetworkDataProviders[0], source, destination);
                    break;
                case SearchType.Greedy_BiDir:
                    searchAlgorithm = new PTGreedySearch(
                        true, this.properties.NetworkDataProviders[0], source, destination);
                    break;
                case SearchType.A_Star_Standard:
                    searchAlgorithm = new PTAStarSearch(
                        false, this.properties.NetworkDataProviders[0], source, destination);
                    break;
                case SearchType.A_Star_BiDir:
                    searchAlgorithm = new PTAStarSearch(
                        true, this.properties.NetworkDataProviders[0], source, destination);
                    break;
                case SearchType.RW_Standard:
                    searchAlgorithm = new PTDepthFirstSearch(
                        false, this.properties.NetworkDataProviders[0], source, destination)
                        {
                            UseVisited = false
                        };
                    break;
                case SearchType.RW_BiDir:
                    searchAlgorithm = new PTDepthFirstSearch(
                        true, this.properties.NetworkDataProviders[0], source, destination)
                        {
                            UseVisited = false
                        };
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
            }

            // PTDepthFirstSearch searchAlgorithm = new PTDepthFirstSearch(properties.Bidirectional,properties.NetworkDataProviders[0],source,destination);
            INetworkNode[] nodes = searchAlgorithm.Run();

            // if (nodes.First() != destination || nodes.Last() != source)
            // {
            // throw new Exception("Path is invalid!");
            // }
            // searchAlgorithm.Entropy = 0.0;
            switch (this.searchType)
            {
                case SearchType.DFS_Standard:
                    nodes = nodes.Reverse().ToArray();
                    break;
                case SearchType.Greedy_Standard:
                    nodes = nodes.Reverse().ToArray();
                    break;
                case SearchType.A_Star_Standard:
                    nodes = nodes.Reverse().ToArray();
                    break;
            }

            // if (!properties.Bidirectional)
            // {

            // }

            // Check for duplicate nodes
            // foreach (var networkNode in nodes)
            // {
            // INetworkNode node = networkNode;
            // var instances = from n in nodes where n.Id == node.Id select n;
            // Assert.True(instances.Count() == 1);
            // }
            return new Route(-1, nodes);
        }
        public TestDFS()
        {
            /*
            Console.WriteLine("Testing simple search on adjacency matrix...");
            var ADFS =
                new AdjacencyDepthFirstSearch(adjacencyMatrix, 0, 5);
            int[] path = ADFS.Run();
            Console.WriteLine("Result: " + String.Join(",\n",path));

            Console.ReadLine();
            */
            var provider = new MetlinkDataProvider();
            INetworkNode[] route = null;
            int depth = 7;

            Stopwatch sw = Stopwatch.StartNew();

            Console.WriteLine("Testing on PT network... (DFS)");
            while (route == null)
            {
                for (int i = 3; i < 11; i++)
                {
                    checked
                    {
                        Console.Write("Solving to depth: {0} entropy {1} --> ", depth++, i / 10.0);
                        long totalIterations = 0;
                        long totalNodes = 0;
                        for (int j = 0; j < 500; j++)
                        {

                            var tdfs = new PTGreedySearch(depth, true, provider, provider.GetNodeFromId(19965), provider.GetNodeFromId(19879));
                            tdfs.Entropy = i / 10.0;
                            route = tdfs.Run();
                            totalIterations += tdfs.Iterations;
                            totalNodes += route.Length;

                        }
                        Console.WriteLine(
                            "Average Iterations: {0} Average Route Length: {1}",
                            totalIterations / 500.0,
                            totalNodes / 500.0);
                    }
                }
            }

            //Console.WriteLine("Result: \n " + String.Join(",\n",route.Cast<object>()) + " Time: " + sw.Elapsed.TotalSeconds + " s");
            Console.WriteLine("Result: Time: " + sw.Elapsed.TotalSeconds + " s  Total nodes: " + route.Length);
            return;
            Console.ReadLine();

            Console.WriteLine("Testing on PT network... (Greedy)");
            sw.Restart();

            route = null;
            depth = 7;
            while (route == null)
            {
                Console.Write("Solving to depth: {0} --> ", depth++);
                INetworkNode origin = provider.GetNodeFromId(19965);
                INetworkNode destination = provider.GetNodeFromId(19879);
                origin.RouteId = provider.GetRoutesForNode(origin)[0];
                destination.RouteId = provider.GetRoutesForNode(destination)[0];
                var tdfs = new PTGreedySearch(depth, true, provider, origin, destination);
                Console.WriteLine("");
                route = tdfs.Run();
                Console.WriteLine("");
                Console.WriteLine("Iterations: " + tdfs.Iterations);
            }
               // Console.WriteLine("Result: \n" + String.Join(", ", route.Cast<object>()) + " Time: " + sw.Elapsed.TotalSeconds + " s  Total nodes: " + route.Length);
            Console.WriteLine("Result: Time: " + sw.Elapsed.TotalSeconds + " s  Total nodes: " + route.Length);
            Console.ReadLine();
            Console.WriteLine("Testing on PT network... (A*)");
            sw.Restart();
            route = null;
            depth = 7;
            while (route == null)
            {
                Console.Write("Solving to depth: {0} --> ", depth++);
                INetworkNode origin = provider.GetNodeFromId(19965);
                INetworkNode destination = provider.GetNodeFromId(19879);
                origin.RouteId = provider.GetRoutesForNode(origin)[0];
                destination.RouteId = provider.GetRoutesForNode(destination)[0];
                var tdfs = new PTAStarSearch(depth,true, provider, origin, destination);
                Console.WriteLine("");
                route = tdfs.Run();
                Console.WriteLine("");
                Console.WriteLine("Iterations: " + tdfs.Iterations);
            }

            //Console.WriteLine("Result: \n" + String.Join(", ", route.Cast<object>()) + " Time: " + sw.Elapsed.TotalSeconds + " s Total nodes: " + route.Length);
            Console.WriteLine("Result: Time: " + sw.Elapsed.TotalSeconds + " s Total nodes: " + route.Length);
            /*
            Console.WriteLine("Testing on PT network... (Rand)");
            sw.Restart();
            route = null;
            depth = 7;
            while (route == null)
            {
                Console.Write("Solving to depth: {0} --> ", depth++);
                INetworkNode origin = provider.GetNodeFromId(19965);
                INetworkNode destination = provider.GetNodeFromId(19842);
                origin.RouteId = provider.GetRoutesForNode(origin)[0];
                destination.RouteId = provider.GetRoutesForNode(destination)[0];
                var tdfs = new RandDepthFirstSearch(false, depth, provider, origin, destination);
                Console.WriteLine("");
                route = tdfs.Run();
                Console.WriteLine("");
                Console.WriteLine("Iterations: " + tdfs.Iterations);
            }

            Console.WriteLine("Result: " + String.Join(",\n", route.Cast<object>()) + " Time: " + sw.Elapsed.TotalSeconds + " s");
            */
        }