/**
         * Construct airportTree, cityTree, and countryTree
         * REQUIREMENT: 
         * 1. The list of airports should be constructed first
         */
        public void constructAirportTrees()
        {
            // if error occured when loading the airports
            // skip this step
            if (_currentState == State.ERROR) return;

            // initialize the fields
            airportTree = new PatriciaTrie<AirportObject.Airport>();
            cityTree = new PatriciaTrie<AirportObject.Airport>();
            countryTree = new PatriciaTrie<AirportObject.Airport>();

            for (int i = 0; i < airports.Count; i++)
            {
                AirportObject.Airport a = airports[i];

                // skip it the airport name is null
                if (a.name == null) continue;

                // insert airport name, city, and country to each tree
                airportTree.Add(a.name.ToLower(), a);
                cityTree.Add(a.city.ToLower(), a);
                countryTree.Add(a.country.ToLower(), a);
            }

            // set the final state
            currentState = State.READY;
        }
        public void TestPrefix()
        {
            var trie        = new PatriciaTrie <string>();
            var tokyoPlaces = new string[] {
                "Hachiōji",
                "Tachikawa",
                "Musashino",
                "Mitaka",
                "Ōme",
                "Fuchū",
                "Akishima",
                "Chōfu",
                "Machida",
                "Koganei",
                "Kodaira",
                "Hino",
                "Higashimurayama",
                "Kokubunji",
                "Kunitachi",
                "Fussa",
                "Komae",
                "Higashiyamato",
                "Kiyose",
                "Higashikurume",
                "Musashimurayama",
                "Tama",
                "Inagi",
                "Hamura",
                "Akiruno",
                "Nishitōkyō"
            };

            foreach (var place in tokyoPlaces)
            {
                trie.Add(place, place);
            }

            // Prefixes of Kodaira
            trie.ContainsKeyPrefix("K").IsTrue();
            trie.ContainsKeyPrefix("Ko").IsTrue();
            trie.ContainsKeyPrefix("Kod").IsTrue();
            trie.ContainsKeyPrefix("Koda").IsTrue();
            trie.ContainsKeyPrefix("Kodai").IsTrue();
            trie.ContainsKeyPrefix("Kodair").IsTrue();
            trie.ContainsKeyPrefix("Kodaira").IsTrue();
            trie.ContainsKeyPrefix("Kodaira ").IsFalse();
            trie.ContainsKeyPrefix("Kodaira  ").IsFalse();
            trie["Kodaira"].IsNotNull();

            // Prefixes of Fussa
            trie.ContainsKeyPrefix("fu").IsFalse();
            trie.ContainsKeyPrefix("Fu").IsTrue();
            trie.ContainsKeyPrefix("Fus").IsTrue();
        }
        public void TestTextScan()
        {
            var trie  = new PatriciaTrie <string>();
            var terms = new string[] {
                "お寿司", "sushi",
                "美味しい", "tasty",
                "日本", "japan",
                "だと思います", "i think",
                "料理", "food",
                "日本料理", "japanese food",
                "一番", "first and foremost",
            };

            for (var i = 0; i < terms.Length; i += 2)
            {
                trie.Add(terms[i], terms[i + 1]);
            }

            var text    = "日本料理の中で、一番美味しいのはお寿司だと思います。すぐ日本に帰りたいです。";
            var builder = new StringBuilder();

            var startIndex = 0;

            while (startIndex < text.Length)
            {
                int matchLength = 0;
                while (trie.ContainsKeyPrefix(text.Substring(startIndex, matchLength + 1)))
                {
                    matchLength++;
                }
                if (matchLength > 0)
                {
                    var match = text.Substring(startIndex, matchLength);
                    builder.Append("[");
                    builder.Append(match);
                    builder.Append("|");
                    builder.Append(trie[match]);
                    builder.Append("]");
                    startIndex += matchLength;
                }
                else
                {
                    builder.Append(text[startIndex]);
                    startIndex++;
                }
            }
            builder.ToString().Is("[日本料理|japanese food]の中で、[一番|first and foremost][美味しい|tasty]のは[お寿司|sushi][だと思います|i think]。すぐ[日本|japan]に帰りたいです。");
        }
        public void TestMultiThreadedTrie()
        {
            var numThreads    = 10;
            var perThreadRuns = 50000;
            var keySetSize    = 1000;

            var threads = new List <Task>();
            var randoms = Enumerable.Range(0, keySetSize).Select(_ => Guid.NewGuid().ToString()).ToArray();

            var trie = new PatriciaTrie <int>();

            for (var i = 0; i < keySetSize; i++)
            {
                trie.Add(randoms[i], i);
            }

            for (int i = 0; i < numThreads; i++)
            {
                var thread = Task.Run(() =>
                {
                    var rand = new Random();
                    for (int run = 0; run < perThreadRuns; run++)
                    {
                        int randomIndex = rand.Next(randoms.Length);
                        var random      = randoms[randomIndex];

                        // Test retrieve
                        trie[random].Is(randomIndex);

                        int randomPrefixLength = rand.Next(random.Length);

                        // Test random prefix length prefix match
                        trie.ContainsKeyPrefix(random.Substring(0, randomPrefixLength)).IsTrue();
                    }
                });
                threads.Add(thread);
            }

            Task.WaitAll(threads.ToArray());

            true.IsTrue();
        }
        public void TestRandom()
        {
            // Generate random strings
            var randoms = Enumerable.Range(0, 10000).Select(_ => Guid.NewGuid().ToString()).ToArray();

            // Insert them
            var trie = new PatriciaTrie <string>();

            foreach (var random in randoms)
            {
                trie.Add(random, random);
            }

            // Get and test them
            foreach (var random in randoms)
            {
                trie[random].Is(random);
                trie.ContainsKey(random).IsTrue();
            }
        }
        private static ITrie <int> GetTrieWithData()
        {
            var randomizer = new Random();
            var words      = new Dictionary <string, int>
            {
                { "арбуз", randomizer.Next() },
                { "аркебуза", randomizer.Next() },
                { "арбузяка", randomizer.Next() },
                { "арбузка", randomizer.Next() },
                { "арбузяшка", randomizer.Next() },
                { "арлекин", randomizer.Next() },
                { "аптека", randomizer.Next() },
            };
            var trie = new PatriciaTrie <int>();

            foreach (var kv in words)
            {
                trie.Add(kv.Key, kv.Value);
            }

            return(trie);
        }