/// <summary>
        /// _polyfillInternal traces the provided geoPolygon data structure with hexagons
        /// and then iteratively searches through these hexagons and their immediate
        /// neighbors to see if they are contained within the polygon or not. Those that
        /// are found are added to the out array as well as the found array. Once all
        /// hexagons to search are checked, the found hexagons become the new search
        /// array and the found array is wiped and the process repeats until no new
        /// hexagons can be found.
        /// </summary>
        /// <remarks>
        /// This comes at it a little differently using C#'s internal HashSet rather
        /// than a collision bucket.  I've tweaked it to where it matches the speed
        /// of the original in benchmark tests, but it liekly could be made faster.
        /// </remarks>
        /// <param name="polygon">The geofence and holes defining the relevant area</param>
        /// <param name="res">The Hexagon resolution (0-15)</param>
        /// <returns>
        /// Tuple
        /// Item1 - Status code
        /// Item2 - List of H3Index values
        /// </returns>
        /// <!--
        /// algos.c
        /// int _polyfillInternal
        /// -->
        public static (int, List <H3Index>) PolyFillInternal(this GeoPolygon polygon, int res)
        {
            //  Get bounding boxes
            var bboxes = polygon.ToBBoxes();

            // Get the traced hexagons around the outer polygon;
            var geofence = polygon.GeoFence;

            var preSearch = new List <H3Index>();
            var search    = geofence.GetEdgeHexagons(res);

            preSearch.AddRange(search);

            //  Check inner holes
            for (var i = 0; i < polygon.NumHoles; i++)
            {
                var hole     = polygon.Holes[i];
                var innerHex = hole.GetEdgeHexagons(res);
                preSearch.AddRange(innerHex);
            }

            search = new HashSet <H3Index>();
            search.UnionWith(preSearch);

            var found          = new HashSet <H3Index>();
            var results        = new HashSet <H3Index>();
            int numSearchHexes = search.Count;
            var numFoundHexes  = 0;

            while (numSearchHexes > 0)
            {
                var currentSearchNum = 0;
                while (currentSearchNum < numSearchHexes)
                {
                    foreach (var ring in search
                             .Select
                             (
                                 index => index.KRing(1)
                                 .Where(h => h != Constants.H3Index.H3_NULL)
                             ))
                    {
                        foreach (
                            var hex in ring
                            .Where
                            (
                                hex => !results.Contains(hex) &&
                                !found.Contains(hex) &&
                                polygon.PointInside(bboxes, hex.ToGeoCoord())
                            ))
                        {
                            found.Add(hex);
                            numFoundHexes++;
                        }

                        currentSearchNum++;
                    }
                }

                search         = new HashSet <H3Index>(found);
                numSearchHexes = numFoundHexes;
                numFoundHexes  = 0;
                results.UnionWith(found);
                found.Clear();
            }

            return(0, results.ToList());
        }