namespace Timed;

public class KeyWatcher : IObservable<char>
{
    private readonly List<Subscription> _subscriptions = new();

    public IDisposable Subscribe(IObserver<char> observer)
    {
        var sub = new Subscription(this, observer);
        _subscriptions.Add(sub);
        return sub;
    }

    public void Run()
    {
        while (true)
        {
            // Przekazanie tu wartości true sprawi, że na konsoli nie będą wyświetlane znaki
            char c = Console.ReadKey(true).KeyChar;

            // Wywołanie ToArray pozwala nam na przeglądanie kopii listy subskrybentów.
            // To rozwiązanie zapewnia możliwość obsługi sytuacji, gdy obserwator
            // anuluje subskrypcję w trakcie rozsyłania powiadomień
            foreach (Subscription sub in _subscriptions.ToArray())
            {
                sub.Observer.OnNext(c);
            }
        }
    }

    private void RemoveSubscription(Subscription sub)
    {
        _subscriptions.Remove(sub);
    }

    private class Subscription : IDisposable
    {
        private KeyWatcher? _parent;
        public Subscription(KeyWatcher parent, IObserver<char> observer)
        {
            _parent = parent;
            Observer = observer;
        }

        public IObserver<char> Observer { get; }

        public void Dispose()
        {
            if (_parent != null)
            {
                _parent.RemoveSubscription(this);
                _parent = null;
            }
        }
    }
}