using System;

namespace Renci.SshNet.Common
{
    /// <summary>
    /// Base class to encapsulates the results of an asynchronous operation that returns result.
    /// </summary>
    /// <typeparam name="TResult">The type of the result.</typeparam>
    public abstract class AsyncResult<TResult> : AsyncResult
    {
        // Field set when operation completes
        private TResult _result;

        /// <summary>
        /// Initializes a new instance of the <see cref="AsyncResult{TResult}"/> class.
        /// </summary>
        /// <param name="asyncCallback">The async callback.</param>
        /// <param name="state">The state.</param>
        protected AsyncResult(AsyncCallback asyncCallback, object state)
            : base(asyncCallback, state)
        {
        }

        /// <summary>
        /// Marks asynchronous operation as completed.
        /// </summary>
        /// <param name="result">The result.</param>
        /// <param name="completedSynchronously">if set to <see langword="true"/> [completed synchronously].</param>
        public void SetAsCompleted(TResult result, bool completedSynchronously)
        {
            // Save the asynchronous operation's result
            _result = result;

            // Tell the base class that the operation completed successfully (no exception)
            SetAsCompleted(exception: null, completedSynchronously);
        }

        /// <summary>
        /// Waits until the asynchronous operation completes, and then returns the value generated by the asynchronous operation.
        /// </summary>
        /// <returns>
        /// The invocation result.
        /// </returns>
        public new TResult EndInvoke()
        {
            base.EndInvoke(); // Wait until operation has completed
            return _result;  // Return the result (if above didn't throw)
        }
    }
}
