/// <summary>
        /// Create intersection with another option
        /// </summary>
        /// <param name="option"></param>
        /// <returns>this if <paramref name="option"/> is null or new instance with intersection</returns>
        public virtual AllOptions Intersection(IOption option)
        {
            if (option == null)
            {
                return(this);
            }
            AllOptions result = new AllOptions();

            result.CanBrowse           = this.CanBrowse | option.CanBrowse();
            result.CanGetEntry         = this.CanGetEntry | option.CanGetEntry();
            result.CanObserve          = this.CanObserve | option.CanObserve();
            result.CanOpen             = this.CanOpen | option.CanOpen();
            result.CanRead             = this.CanRead | option.CanRead();
            result.CanWrite            = this.CanWrite | option.CanWrite();
            result.CanCreateFile       = this.CanCreateFile | option.CanCreateFile();
            result.CanDelete           = this.CanDelete | option.CanDelete();
            result.CanSetFileAttribute = this.CanSetFileAttribute | option.CanSetFileAttribute();
            result.CanMount            = this.CanMount | option.CanMount();
            result.CanCreateFile       = this.CanCreateFile | option.CanCreateFile();
            result.CanDelete           = this.CanDelete | option.CanDelete();
            result.CanMove             = this.CanMove | option.CanMove();
            result.CanCreateDirectory  = this.CanCreateDirectory | option.CanCreateDirectory();
            result.CanMount            = this.CanMount | option.CanMount();
            result.CanUnmount          = this.CanUnmount | option.CanUnmount();
            result.CanListMountPoints  = this.CanListMountPoints | option.CanListMountPoints();
            result.SubPath             = this.SubPath ?? option.SubPath();
            return(result);
        }
 /// <summary>
 /// Read options from <paramref name="option"/> and return flattened object.
 /// </summary>
 /// <param name="option"></param>
 /// <returns></returns>
 public virtual void ReadFrom(IOption option)
 {
     this.CanBrowse           = option.CanBrowse();
     this.CanGetEntry         = option.CanGetEntry();
     this.CanObserve          = option.CanObserve();
     this.CanOpen             = option.CanOpen();
     this.CanRead             = option.CanRead();
     this.CanWrite            = option.CanWrite();
     this.CanCreateFile       = option.CanCreateFile();
     this.CanDelete           = option.CanDelete();
     this.CanMove             = option.CanMove();
     this.CanCreateDirectory  = option.CanCreateDirectory();
     this.CanMount            = option.CanMount();
     this.CanUnmount          = option.CanUnmount();
     this.CanListMountPoints  = option.CanListMountPoints();
     this.SubPath             = option.SubPath();
     this.CanSetFileAttribute = option.CanSetFileAttribute();
 }
        /// <summary>
        /// Attach an <paramref name="observer"/> on to a single file or directory.
        /// Observing a directory will observe the whole subtree.
        ///
        /// WARNING: The Observe implementation browses the subtree of the watched directory path in order to create delta of changes.
        /// </summary>
        /// <param name="filter">path to file or directory. The directory separator is "/". The root is without preceding slash "", e.g. "dir/dir2"</param>
        /// <param name="observer"></param>
        /// <param name="state">(optional) </param>
        /// <param name="eventDispatcher">(optional) event dispatcher</param>
        /// <param name="option">(optional) operation specific option; capability constraint, a session, security token or credential. Used for authenticating, authorizing or restricting the operation.</param>
        /// <returns>dispose handle</returns>
        /// <exception cref="IOException">On unexpected IO error</exception>
        /// <exception cref="SecurityException">If caller did not have permission</exception>
        /// <exception cref="ArgumentNullException"><paramref name="filter"/> is null</exception>
        /// <exception cref="ArgumentException"><paramref name="filter"/> contains only white space, or contains one or more invalid characters</exception>
        /// <exception cref="NotSupportedException">The <see cref="IFileSystem"/> doesn't support observe</exception>
        /// <exception cref="UnauthorizedAccessException">The access requested is not permitted by the operating system for the specified path.</exception>
        /// <exception cref="PathTooLongException">The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters.</exception>
        /// <exception cref="InvalidOperationException">If <paramref name="filter"/> refers to a non-file device, such as "con:", "com1:", "lpt1:", etc.</exception>
        /// <exception cref="ObjectDisposedException"/>
        public virtual IFileSystemObserver Observe(string filter, IObserver <IEvent> observer, object state = null, IEventDispatcher eventDispatcher = default, IOption option = null)
        {
            // Assert observe is enabled.
            if (!CanObserve || !option.CanObserve(true))
            {
                throw new NotSupportedException(nameof(Observe));
            }
            // Assert not diposed
            IFileProvider fp = fileProvider;

            if (fp == null)
            {
                return(new DummyObserver(this, filter, observer, state, eventDispatcher));
            }
            // Parse filter
            GlobPatternInfo patternInfo = new GlobPatternInfo(filter);

            // Monitor single file (or dir, we don't know "dir")
            if (patternInfo.SuffixDepth == 0)
            {
                // Create observer that watches one file
                FileObserver handle = new FileObserver(this, filter, observer, state, eventDispatcher, option.OptionIntersection(this.options));
                // Send handle
                observer.OnNext(new StartEvent(handle, DateTimeOffset.UtcNow));
                // Return handle
                return(handle);
            }
            else
            // Has wildcards, e.g. "**/file.txt"
            {
                // Create handle
                PatternObserver handle = new PatternObserver(this, patternInfo, observer, state, eventDispatcher);
                // Send handle
                observer.OnNext(new StartEvent(handle, DateTimeOffset.UtcNow));
                // Return handle
                return(handle);
            }
        }