/// <summary>
        /// Get the surface with the highest priority for retrieving the mesh. Surfaces
        /// without meshes are prioritized before those with outdated ones, and older
        /// ones are prioritized before newer ones.
        /// </summary>
        /// <returns></returns>
        private ISpatialSurface GetHighestPrioritySurface()
        {
            ISpatialSurface highestPrioritySurface = null;

            foreach (KeyValuePair <int, ISpatialSurface> surface in _surfaceEntries)
            {
                // Only consider surfaces with out of date/without meshes
                if (surface.Value.MeshStatus != SurfaceMeshStatuses.UP_TO_DATE)
                {
                    if (highestPrioritySurface == null)
                    {
                        highestPrioritySurface = surface.Value;
                    }
                    else
                    {
                        // Missing meshes before outdated meshes
                        if (surface.Value.MeshStatus < highestPrioritySurface.MeshStatus)
                        {
                            highestPrioritySurface = surface.Value;
                        }
                        // Older meshes first
                        else if (surface.Value.UpdateTime < highestPrioritySurface.UpdateTime)
                        {
                            highestPrioritySurface = surface.Value;
                        }
                    }
                }
            }
            return(highestPrioritySurface);
        }
        /// <summary>
        /// Checks if the surface observer needs to be updated, if a new mesh request should be started,
        /// finds the surface with highest priority, and sends a new request for a mesh
        /// </summary>
        private void Update()
        {
            if (_doUpdates)
            {
                // Updating the surface observer is a very expensive procedure, so only do it at the specified intervals
                if (Time.realtimeSinceStartup > _previousUpdate + _updateInterval)
                {
                    UpdateBoundingVolume();

                    try
                    {
                        _surfaceObserver.Update(SurfaceChangedHandler);
                    }
                    catch
                    {
                        // Bad callbacks can throw errors
                        Debug.LogError("SpatialMapper Error: Unexpected failure when updating the surface observer!");
                    }

                    _previousUpdate = Time.realtimeSinceStartup;
                }

                // If there is no current mesh request, start a new one
                if (!_meshRequestInProgress)
                {
                    ISpatialSurface highestPrioritySurface = GetHighestPrioritySurface();

                    if (highestPrioritySurface != null)
                    {
                        SurfaceData sd;
                        sd.id.handle              = highestPrioritySurface.Id;
                        sd.outputMesh             = highestPrioritySurface.Mesh;
                        sd.outputCollider         = highestPrioritySurface.Collider;
                        sd.outputAnchor           = highestPrioritySurface.Anchor;
                        sd.trianglesPerCubicMeter = _trianglesPerCubicMeter;
                        sd.bakeCollider           = sd.outputCollider != null;

                        try
                        {
                            if (_surfaceObserver.RequestMeshAsync(sd, SurfaceDataReadyHandler))
                            {
                                _meshRequestInProgress = true;
                            }
                            else
                            {
                                Debug.LogErrorFormat("SpatialMapper Error: Mesh request for {0} failed. Check that {0} is a valid Surface ID.", sd.id);
                            }
                        }
                        catch
                        {
                            // Failure can happen if the data structure is filled out wrong
                            Debug.LogErrorFormat("SpatialMapper Error: Mesh request for {0} failed unexpectedly.", sd.id);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// This method handles observed changes to surfaces (added, updated, or removed).
        /// These changes have their source in the update loop where the surface observer
        /// is updated.
        /// </summary>
        /// <param name="id">The unique id of the surface</param>
        /// <param name="changeType">Says if the surface has been added, updated, or removed</param>
        /// <param name="bounds">The axis aligned bounding box containing the surface</param>
        /// <param name="updateTime">Time of the update</param>
        private void SurfaceChangedHandler(SurfaceId id, SurfaceChange changeType, Bounds bounds, DateTime updateTime)
        {
            ISpatialSurface surface = null;

            switch (changeType)
            {
            case SurfaceChange.Added:
            case SurfaceChange.Updated:
                if (_surfaceEntries.TryGetValue(id.handle, out surface))
                {
                    if (surface.MeshStatus == SurfaceMeshStatuses.UP_TO_DATE)
                    {
                        surface.MeshStatus = SurfaceMeshStatuses.OUTDATED;
                        surface.UpdateTime = updateTime;
                    }
                }
                else
                {
                    surface = _surfaceEntryFactory.Create(updateTime, id.handle, _castShadows, _recieveShadows, _meshMaterial, _addColliders, _physicMaterial);
                    surface.Instance.transform.SetParent(_meshParent != null ? _meshParent : transform, false);
                    _surfaceEntries[id.handle] = surface;
                }
                break;

            case SurfaceChange.Removed:
                if (_surfaceEntries.TryGetValue(id.handle, out surface))
                {
                    _surfaceEntries.Remove(id.handle);
                    Mesh mesh = surface.Mesh.mesh;
                    if (mesh)
                    {
                        Destroy(mesh);
                    }
                    Destroy(surface.Instance);
                }
                break;

            default:
                break;
            }
        }