﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Threading;

namespace Microsoft.CodeAnalysis.Editor.Shared.Utilities
{
    /// <summary>
    /// Provides a <see cref="VisualStudio.Threading.JoinableTaskContext"/> which Roslyn code can use for transitioning
    /// to the main thread and/or waiting for asynchronous operations when required.
    /// </summary>
    internal interface IThreadingContext
    {
        /// <summary>
        /// Gets a value indicating whether the threading context is configured with a main thread that can be used for
        /// scheduling operations.
        /// </summary>
        /// <remarks>
        /// <para>Existence of a main thread is a requirement for correct runtime behavior (in production) of all types
        /// that depend on <see cref="IThreadingContext"/>, so code is generally not expected to check this property.
        /// However, in some lightweight testing scenarios the main thread will not be used, and the test code avoids
        /// setting up the main thread. This property improves the ability to detect incorrectly configured tests (where
        /// a main thread is expected but not provided) and produce a meaningful error for developers.</para>
        /// </remarks>
        bool HasMainThread
        {
            get;
        }

        /// <summary>
        /// Gets the <see cref="VisualStudio.Threading.JoinableTaskContext"/> for use in Roslyn code.
        /// </summary>
        JoinableTaskContext JoinableTaskContext
        {
            get;
        }

        /// <summary>
        /// Gets the <see cref="VisualStudio.Threading.JoinableTaskFactory"/> for use in Roslyn code.
        /// </summary>
        JoinableTaskFactory JoinableTaskFactory
        {
            get;
        }

        /// <summary>
        /// Gets a <see cref="CancellationToken"/> indicating that disposal has been requested for the threading
        /// context.
        /// </summary>
        CancellationToken DisposalToken
        {
            get;
        }

        /// <summary>
        /// Runs an asynchronous operation. If the operation is not complete prior to the time the threading context is
        /// disposed, the operation will block the shutdown.
        /// </summary>
        /// <remarks>
        /// <para>The callback function <paramref name="func"/> is invoked synchronously prior to this method returning.
        /// The entire asynchronous operation performed by <paramref name="func"/> will block shutdown of the threading
        /// context.</para>
        ///
        /// <para>If the threading context is already disposed at the time this is called, the operation is cancelled
        /// without calling <paramref name="func"/>.</para>
        /// </remarks>
        /// <param name="func">The callback function that performs an asynchronous operation.</param>
        JoinableTask RunWithShutdownBlockAsync(Func<CancellationToken, Task> func);
    }
}
