// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// DataflowLinkOptions.cs
//
//
// DataflowLinkOptions type for configuring links between dataflow blocks
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace System.Threading.Tasks.Dataflow
{
    /// <summary>
    /// Provides options used to configure a link between dataflow blocks.
    /// </summary>
    /// <remarks>
    /// <see cref="DataflowLinkOptions"/> is mutable and can be configured through its properties.  
    /// When specific configuration options are not set, the following defaults are used:
    /// <list type="table">
    ///     <listheader>
    ///         <term>Options</term>
    ///         <description>Default</description>
    ///     </listheader>
    ///     <item>
    ///         <term>PropagateCompletion</term>
    ///         <description>False</description>
    ///     </item>
    ///     <item>
    ///         <term>MaxMessages</term>
    ///         <description>DataflowBlockOptions.Unbounded (-1)</description>
    ///     </item>
    ///     <item>
    ///         <term>Append</term>
    ///         <description>True</description>
    ///     </item>
    /// </list>
    /// Dataflow blocks capture the state of the options at linking. Subsequent changes to the provided
    /// <see cref="DataflowLinkOptions"/> instance should not affect the behavior of a link.
    /// </remarks>
    [DebuggerDisplay("PropagateCompletion = {PropagateCompletion}, MaxMessages = {MaxMessages}, Append = {Append}")]
    public class DataflowLinkOptions
    {
        /// <summary>
        /// A constant used to specify an unlimited quantity for <see cref="DataflowLinkOptions"/> members 
        /// that provide an upper bound. This field is a constant tied to <see cref="DataflowLinkOptions.Unbounded"/>.
        /// </summary>
        internal const Int32 Unbounded = DataflowBlockOptions.Unbounded;

        /// <summary>Whether the linked target will have completion and faulting notification propagated to it automatically.</summary>
        private Boolean _propagateCompletion = false;
        /// <summary>The maximum number of messages that may be consumed across the link.</summary>
        private Int32 _maxNumberOfMessages = Unbounded;
        /// <summary>Whether the link should be appended to the source’s list of links, or whether it should be prepended.</summary>
        private Boolean _append = true;

        /// <summary>A default instance of <see cref="DataflowLinkOptions"/>.</summary>
        /// <remarks>
        /// Do not change the values of this instance.  It is shared by all of our blocks when no options are provided by the user.
        /// </remarks>
        internal static readonly DataflowLinkOptions Default = new DataflowLinkOptions();

        /// <summary>A cached instance of <see cref="DataflowLinkOptions"/>.</summary>
        /// <remarks>
        /// Do not change the values of this instance.  It is shared by all of our blocks that need to unlink after one message has been consumed.
        /// </remarks>
        internal static readonly DataflowLinkOptions UnlinkAfterOneAndPropagateCompletion = new DataflowLinkOptions() { MaxMessages = 1, PropagateCompletion = true };

        /// <summary>Initializes the <see cref="DataflowLinkOptions"/>.</summary>
        public DataflowLinkOptions()
        {
        }

        /// <summary>Gets or sets whether the linked target will have completion and faulting notification propagated to it automatically.</summary>
        public Boolean PropagateCompletion
        {
            get { return _propagateCompletion; }
            set
            {
                Debug.Assert(this != Default && this != UnlinkAfterOneAndPropagateCompletion, "Default and UnlinkAfterOneAndPropagateCompletion instances are supposed to be immutable.");
                _propagateCompletion = value;
            }
        }

        /// <summary>Gets or sets the maximum number of messages that may be consumed across the link.</summary>
        public Int32 MaxMessages
        {
            get { return _maxNumberOfMessages; }
            set
            {
                Debug.Assert(this != Default && this != UnlinkAfterOneAndPropagateCompletion, "Default and UnlinkAfterOneAndPropagateCompletion instances are supposed to be immutable.");
                if (value < 1 && value != Unbounded) throw new ArgumentOutOfRangeException("value");
                _maxNumberOfMessages = value;
            }
        }

        /// <summary>Gets or sets whether the link should be appended to the source’s list of links, or whether it should be prepended.</summary>
        public Boolean Append
        {
            get { return _append; }
            set
            {
                Debug.Assert(this != Default && this != UnlinkAfterOneAndPropagateCompletion, "Default and UnlinkAfterOneAndPropagateCompletion instances are supposed to be immutable.");
                _append = value;
            }
        }
    }
}