// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using Microsoft.Build.Shared;

using BuildResult = Microsoft.Build.Execution.BuildResult;

#nullable disable

namespace Microsoft.Build.BackEnd
{
    /// <summary>
    /// This class is used by the Scheduler to unblock a blocked build request on the BuildRequestEngine.
    /// There are two cases:
    /// 1. The request was blocked waiting on a target in the same project.  In this case this class will contain
    ///    no information other than the request id.
    /// 2. The request was blocked on some set of build requests.  This class will then contain the build results
    ///    needed to satisfy those requests.
    /// </summary>
    internal class BuildRequestUnblocker : ITranslatable, INodePacket
    {
        /// <summary>
        /// The node request id of the request which is blocked and now will either result or have results reported.
        /// </summary>
        private int _blockedGlobalRequestId = BuildRequest.InvalidGlobalRequestId;

        /// <summary>
        /// The build result which we wish to report.
        /// </summary>
        private BuildResult _buildResult;

        /// <summary>
        /// Constructor for deserialization.
        /// </summary>
        internal BuildRequestUnblocker(ITranslator translator)
        {
            Translate(translator);
        }

        /// <summary>
        /// Constructor for the unblocker where we are blocked waiting for a target.
        /// </summary>
        internal BuildRequestUnblocker(int globalRequestIdToResume)
        {
            ErrorUtilities.VerifyThrowArgumentOutOfRange(globalRequestIdToResume != BuildRequest.InvalidGlobalRequestId, nameof(globalRequestIdToResume));
            _blockedGlobalRequestId = globalRequestIdToResume;
        }

        /// <summary>
        /// Constructor for the unblocker where we are blocked waiting for results.
        /// </summary>
        internal BuildRequestUnblocker(BuildResult buildResult)
        {
            ErrorUtilities.VerifyThrowArgumentNull(buildResult);
            _buildResult = buildResult;
            _blockedGlobalRequestId = buildResult.ParentGlobalRequestId;
        }

        /// <summary>
        /// Constructor for the unblocker for circular dependencies
        /// </summary>
        internal BuildRequestUnblocker(BuildRequest parentRequest, BuildResult buildResult)
            : this(buildResult)
        {
            ErrorUtilities.VerifyThrowArgumentNull(parentRequest);
            _blockedGlobalRequestId = parentRequest.GlobalRequestId;
        }

        /// <summary>
        /// Returns the type of packet.
        /// </summary>
        public NodePacketType Type
        {
            [DebuggerStepThrough]
            get
            { return NodePacketType.BuildRequestUnblocker; }
        }

        /// <summary>
        /// Accessor for the blocked node request id.
        /// </summary>
        public int BlockedRequestId
        {
            [DebuggerStepThrough]
            get
            {
                return _blockedGlobalRequestId;
            }
        }

        /// <summary>
        /// Accessor for the build results, if any.
        /// </summary>
        public BuildResult Result
        {
            [DebuggerStepThrough]
            get
            {
                return _buildResult;
            }
        }

        #region INodePacketTranslatable Members

        /// <summary>
        /// Serialization method.
        /// </summary>
        public void Translate(ITranslator translator)
        {
            translator.Translate(ref _blockedGlobalRequestId);
            translator.Translate(ref _buildResult);
        }

        #endregion

        /// <summary>
        /// Factory for serialization.
        /// </summary>
        internal static INodePacket FactoryForDeserialization(ITranslator translator)
        {
            return new BuildRequestUnblocker(translator);
        }
    }
}
