<commit_before>﻿using System;
using System.Linq;
using System.Reactive.Linq;
using static LanguageExt.Prelude;
using static LanguageExt.Map;
using LanguageExt;
using System.Collections;

namespace Echo
{
    /// <summary>
    /// <para>
    ///     Process:  Tell functions
    /// </para>
    /// <para>
    ///     'Tell' is used to send a message from one process to another (or from outside a process to a process).
    ///     The messages are sent to the process asynchronously and join the process' inbox.  The process will 
    ///     deal with one message from its inbox at a time.  It cannot start the next message until it's finished
    ///     with a previous message.
    /// </para>
    /// </summary>
    public static partial class Process
    {
        /// <summary>
        /// Send a message to a process
        /// </summary>
        /// <param name="pid">Process ID to send to</param>
        /// <param name="message">Message to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tell<T>(ProcessId pid, T message, ProcessId sender = default(ProcessId)) =>
            message is UserControlMessage
                ? ActorContext.System(pid).TellUserControl(pid, message as UserControlMessage)
                : ActorContext.System(pid).Tell(pid, message, Schedule.Immediate, sender);

        /// <summary>
        /// Send a message to a process
        /// </summary>
        /// <param name="pid">Process ID to send to</param>
        /// <param name="message">Message to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        internal static Unit tellSystem<T>(ProcessId pid, T message, ProcessId sender = default(ProcessId)) =>
            ActorContext.System(pid).TellSystem(pid, message as SystemMessage);

        /// <summary>
        /// Send a message at a specified time in the future
        /// </summary>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        /// <param name="pid">Process ID to send to</param>
        /// <param name="message">Message to send</param>
        /// <param name="schedule">A structure that defines the method of delivery of the scheduled message</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tell<T>(ProcessId pid, T message, Schedule schedule, ProcessId sender = default(ProcessId)) =>
            ActorContext.System(pid).Tell(pid, message, schedule, sender);

        /// <summary>
        /// Send a message at a specified time in the future
        /// </summary>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        /// <param name="pid">Process ID to send to</param>
        /// <param name="message">Message to send</param>
        /// <param name="delayFor">How long to delay sending for</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tell<T>(ProcessId pid, T message, TimeSpan delayFor, ProcessId sender = default(ProcessId)) =>
            ActorContext.System(pid).Tell(pid, message, Schedule.Ephemeral(delayFor), sender);

        /// <summary>
        /// Send a message at a specified time in the future
        /// </summary>
        /// <remarks>
        /// It is advised to use the variant that takes a TimeSpan, this will fail to be accurate across a Daylight Saving 
        /// Time boundary or if you use non-UTC dates
        /// </remarks>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        /// <param name="pid">Process ID to send to</param>
        /// <param name="message">Message to send</param>
        /// <param name="delayUntil">Date and time to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tell<T>(ProcessId pid, T message, DateTime delayUntil, ProcessId sender = default(ProcessId)) =>
            ActorContext.System(pid).Tell(pid, message, Schedule.Ephemeral(delayUntil), sender);

        /// <summary>
        /// Tell children the same message
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tellChildren<T>(T message, ProcessId sender = default(ProcessId)) =>
            Children.Iter(child => tell(child, message, sender));

        /// <summary>
        /// Tell children the same message
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        internal static Unit tellSystemChildren<T>(T message, ProcessId sender = default(ProcessId)) =>
            Children.Iter(child => tellSystem(child, message, sender));

        /// <summary>
        /// Tell children the same message, delayed.
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="schedule">A structure that defines the method of delivery of the scheduled message</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, Schedule schedule, ProcessId sender = default(ProcessId)) =>
            Children.Values.Iter(child => tell(child, message, schedule, sender));

        /// <summary>
        /// Tell children the same message, delayed.
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="delayFor">How long to delay sending for</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, TimeSpan delayFor, ProcessId sender = default(ProcessId)) =>
            Children.Values.Iter(child => tell(child, message, delayFor, sender));

        /// <summary>
        /// Tell children the same message, delayed.
        /// </summary>
        /// <remarks>
        /// This will fail to be accurate across a Daylight Saving Time boundary
        /// </remarks>
        /// <param name="message">Message to send</param>
        /// <param name="delayUntil">Date and time to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, DateTime delayUntil, ProcessId sender = default(ProcessId)) =>
            Children.Values.Iter(child => tell(child, message, delayUntil, sender));

        /// <summary>
        /// Tell children the same message
        /// The list of children to send to are filtered by the predicate provided
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="predicate">The list of children to send to are filtered by the predicate provided</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tellChildren<T>(T message, Func<ProcessId, bool> predicate, ProcessId sender = default(ProcessId)) =>
            Children.Filter(predicate).Iter(child => tell(child, message, sender));

        /// <summary>
        /// Tell children the same message, delayed.
        /// The list of children to send to are filtered by the predicate provided
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="schedule">A structure that defines the method of delivery of the scheduled message</param>
        /// <param name="predicate">The list of children to send to are filtered by the predicate provided</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, Schedule schedule, Func<ProcessId, bool> predicate, ProcessId sender = default(ProcessId)) =>
            Children.Filter(predicate).Values.Iter(child => tell(child, message, schedule, sender));

        /// <summary>
        /// Tell children the same message, delayed.
        /// The list of children to send to are filtered by the predicate provided
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="delayFor">How long to delay sending for</param>
        /// <param name="predicate">The list of children to send to are filtered by the predicate provided</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, TimeSpan delayFor, Func<ProcessId, bool> predicate, ProcessId sender = default(ProcessId)) =>
            Children.Filter(predicate).Values.Iter(child => tell(child, message, delayFor, sender));

        /// <summary>
        /// Tell children the same message, delayed.
        /// The list of children to send to are filtered by the predicate provided
        /// </summary>
        /// <remarks>
        /// This will fail to be accurate across a Daylight Saving Time boundary
        /// </remarks>
        /// <param name="message">Message to send</param>
        /// <param name="delayUntil">Date and time to send</param>
        /// <param name="predicate">The list of children to send to are filtered by the predicate provided</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, DateTime delayUntil, Func<ProcessId, bool> predicate, ProcessId sender = default(ProcessId)) =>
            Children.Filter(predicate).Values.Iter(child => tell(child, message, delayUntil, sender));

        /// <summary>
        /// Send a message to the parent process
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tellParent<T>(T message, ProcessId sender = default(ProcessId)) =>
            tell(Parent, message, sender);

        /// <summary>
        /// Send a message to the parent process at a specified time in the future
        /// </summary>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        /// <param name="message">Message to send</param>
        /// <param name="schedule">A structure that defines the method of delivery of the scheduled message</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tellParent<T>(T message, Schedule schedule, ProcessId sender = default(ProcessId)) =>
            tell(Parent, message, schedule, sender);

        /// <summary><commit_msg>Safe telling of children<commit_after>﻿using System;
using System.Linq;
using System.Reactive.Linq;
using static LanguageExt.Prelude;
using static LanguageExt.Map;
using LanguageExt;
using System.Collections;

namespace Echo
{
    /// <summary>
    /// <para>
    ///     Process:  Tell functions
    /// </para>
    /// <para>
    ///     'Tell' is used to send a message from one process to another (or from outside a process to a process).
    ///     The messages are sent to the process asynchronously and join the process' inbox.  The process will 
    ///     deal with one message from its inbox at a time.  It cannot start the next message until it's finished
    ///     with a previous message.
    /// </para>
    /// </summary>
    public static partial class Process
    {
        /// <summary>
        /// Send a message to a process
        /// </summary>
        /// <param name="pid">Process ID to send to</param>
        /// <param name="message">Message to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tell<T>(ProcessId pid, T message, ProcessId sender = default(ProcessId)) =>
            message is UserControlMessage
                ? ActorContext.System(pid).TellUserControl(pid, message as UserControlMessage)
                : ActorContext.System(pid).Tell(pid, message, Schedule.Immediate, sender);

        /// <summary>
        /// Send a message to a process
        /// </summary>
        /// <param name="pid">Process ID to send to</param>
        /// <param name="message">Message to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        internal static Unit tellSystem<T>(ProcessId pid, T message, ProcessId sender = default(ProcessId)) =>
            ActorContext.System(pid).TellSystem(pid, message as SystemMessage);

        /// <summary>
        /// Send a message at a specified time in the future
        /// </summary>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        /// <param name="pid">Process ID to send to</param>
        /// <param name="message">Message to send</param>
        /// <param name="schedule">A structure that defines the method of delivery of the scheduled message</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tell<T>(ProcessId pid, T message, Schedule schedule, ProcessId sender = default(ProcessId)) =>
            ActorContext.System(pid).Tell(pid, message, schedule, sender);

        /// <summary>
        /// Send a message at a specified time in the future
        /// </summary>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        /// <param name="pid">Process ID to send to</param>
        /// <param name="message">Message to send</param>
        /// <param name="delayFor">How long to delay sending for</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tell<T>(ProcessId pid, T message, TimeSpan delayFor, ProcessId sender = default(ProcessId)) =>
            ActorContext.System(pid).Tell(pid, message, Schedule.Ephemeral(delayFor), sender);

        /// <summary>
        /// Send a message at a specified time in the future
        /// </summary>
        /// <remarks>
        /// It is advised to use the variant that takes a TimeSpan, this will fail to be accurate across a Daylight Saving 
        /// Time boundary or if you use non-UTC dates
        /// </remarks>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        /// <param name="pid">Process ID to send to</param>
        /// <param name="message">Message to send</param>
        /// <param name="delayUntil">Date and time to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tell<T>(ProcessId pid, T message, DateTime delayUntil, ProcessId sender = default(ProcessId)) =>
            ActorContext.System(pid).Tell(pid, message, Schedule.Ephemeral(delayUntil), sender);

        /// <summary>
        /// Tell children the same message
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tellChildren<T>(T message, ProcessId sender = default(ProcessId)) =>
            Children.Iter(child => {
                              try
                              {
                                  tell(child, message, sender);
                              }
                              catch
                              {
                                  // Children may change as we're telling, so ignore failures
                                  return;
                              }
                          });

        /// <summary>
        /// Tell children the same message
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        internal static Unit tellSystemChildren<T>(T message, ProcessId sender = default(ProcessId)) =>
            Children.Iter(child => {
                              try
                              {
                                  tellSystem(child, message, sender);
                              }
                              catch
                              {
                                  // Children may change as we're telling, so ignore failures
                                  return;
                              }
                          });

        /// <summary>
        /// Tell children the same message, delayed.
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="schedule">A structure that defines the method of delivery of the scheduled message</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, Schedule schedule, ProcessId sender = default(ProcessId)) =>
            Children.Values.Iter(child => {
                                     try
                                     {
                                         tell(child, message, schedule, sender);
                                     }
                                     catch
                                     {
                                         // Children may change as we're telling, so ignore failures
                                         return;
                                     }
                                 });

        /// <summary>
        /// Tell children the same message, delayed.
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="delayFor">How long to delay sending for</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, TimeSpan delayFor, ProcessId sender = default(ProcessId)) =>
            Children.Values.Iter(child => {
                                     try
                                     {
                                         tell(child, message, delayFor, sender);
                                     }
                                     catch
                                     {
                                         // Children may change as we're telling, so ignore failures
                                         return;
                                     }
                                 });

        /// <summary>
        /// Tell children the same message, delayed.
        /// </summary>
        /// <remarks>
        /// This will fail to be accurate across a Daylight Saving Time boundary
        /// </remarks>
        /// <param name="message">Message to send</param>
        /// <param name="delayUntil">Date and time to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, DateTime delayUntil, ProcessId sender = default(ProcessId)) =>
            Children.Values.Iter(child => {
                                     try
                                     {
                                         tell(child, message, delayUntil, sender);
                                     }
                                     catch
                                     {
                                         // Children may change as we're telling, so ignore failures
                                         return;
                                     }
                                 });

        /// <summary>
        /// Tell children the same message
        /// The list of children to send to are filtered by the predicate provided
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="predicate">The list of children to send to are filtered by the predicate provided</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tellChildren<T>(T message, Func<ProcessId, bool> predicate, ProcessId sender = default(ProcessId)) =>
            Children.Filter(predicate).Iter(child => {
                                                try
                                                {
                                                    tell(child, message, sender);
                                                }
                                                catch
                                                {
                                                    // Children may change as we're telling, so ignore failures
                                                    return;
                                                }
                                            });

        /// <summary>
        /// Tell children the same message, delayed.
        /// The list of children to send to are filtered by the predicate provided
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="schedule">A structure that defines the method of delivery of the scheduled message</param>
        /// <param name="predicate">The list of children to send to are filtered by the predicate provided</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, Schedule schedule, Func<ProcessId, bool> predicate, ProcessId sender = default(ProcessId)) =>
            Children.Filter(predicate).Values.Iter(child => {
                                                       try
                                                       {
                                                           tell(child, message, schedule, sender);
                                                       }
                                                       catch
                                                       {
                                                           // Children may change as we're telling, so ignore failures
                                                           return;
                                                       }
                                                   });

        /// <summary>
        /// Tell children the same message, delayed.
        /// The list of children to send to are filtered by the predicate provided
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="delayFor">How long to delay sending for</param>
        /// <param name="predicate">The list of children to send to are filtered by the predicate provided</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, TimeSpan delayFor, Func<ProcessId, bool> predicate, ProcessId sender = default(ProcessId)) =>
            Children.Filter(predicate).Values.Iter(child => {
                                                       try
                                                       {
                                                           tell(child, message, delayFor, sender);
                                                       }
                                                       catch
                                                       {
                                                           // Children may change as we're telling, so ignore failures
                                                           return;
                                                       }
                                                   });

        /// <summary>
        /// Tell children the same message, delayed.
        /// The list of children to send to are filtered by the predicate provided
        /// </summary>
        /// <remarks>
        /// This will fail to be accurate across a Daylight Saving Time boundary
        /// </remarks>
        /// <param name="message">Message to send</param>
        /// <param name="delayUntil">Date and time to send</param>
        /// <param name="predicate">The list of children to send to are filtered by the predicate provided</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        public static Unit tellChildren<T>(T message, DateTime delayUntil, Func<ProcessId, bool> predicate, ProcessId sender = default(ProcessId)) =>
            Children.Filter(predicate).Values.Iter(child => {
                                                       try
                                                       {
                                                           tell(child, message, delayUntil, sender);
                                                       }
                                                       catch
                                                       {
                                                           // Children may change as we're telling, so ignore failures
                                                           return;
                                                       }
                                                   });

        /// <summary>
        /// Send a message to the parent process
        /// </summary>
        /// <param name="message">Message to send</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tellParent<T>(T message, ProcessId sender = default(ProcessId)) =>
            tell(Parent, message, sender);

        /// <summary>
        /// Send a message to the parent process at a specified time in the future
        /// </summary>
        /// <returns>IDisposable that you can use to cancel the operation if necessary.  You do not need to call Dispose 
        /// for any other reason.</returns>
        /// <param name="message">Message to send</param>
        /// <param name="schedule">A structure that defines the method of delivery of the scheduled message</param>
        /// <param name="sender">Optional sender override.  The sender is handled automatically if you do not provide one.</param>
        public static Unit tellParent<T>(T message, Schedule schedule, ProcessId sender = default(ProcessId)) =>
            tell(Parent, message, schedule, sender);

        /// <summary>
{'fraction_non_alphanumeric': 0.10071517616954268, 'fraction_numerical': 0.0, 'mean_word_length': 1.6680962800875274, 'pattern_counts': {'":': 0, '<': 377, '<?xml version=': 0, '>': 427, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 125, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6786818', 'n_tokens_mistral': 6632, 'n_tokens_neox': 6484, 'n_words': 2704}