using System;
using System.Collections.Generic;
using System.Threading;

namespace _09_PredictiveDialer
{
    class Autodialer
    {
        Softphone _softphone;
        List<CallInfo> _callList;
        int _maxConcurrentCall;
        int _currentConcurrentCall;
        List<CallHandler> _callHandlers;
        AutoResetEvent _autoResetEvent;
        AutoResetEvent _nextCall;
        object _sync;

        bool _firstCall;

        public Autodialer(Softphone softphone, List<CallInfo> callList, int maxConcurrentCall)
        {
            _sync = new object();
            _softphone = softphone;
            _callList = callList;
            _maxConcurrentCall = maxConcurrentCall;
            _callHandlers = new List<CallHandler>();
            _autoResetEvent = new AutoResetEvent(false);
            _nextCall = new AutoResetEvent(false);

            _firstCall = true;
        }

        public void Start()
        {
            StartCall();
        }

        void StartCall()
        {
            ThreadPool.QueueUserWorkItem(o =>
            {
                if (_callList.Count > 0)
                {
                    foreach (var callInfo in _callList)
                    {
                        if (_currentConcurrentCall < _maxConcurrentCall)
                        {
                            if (_firstCall)
                            {
                                _firstCall = false;
                                StartCallHandler(callInfo);
                            }
                            else
                            {
                                _nextCall.WaitOne();
                                StartCallHandler(callInfo);
                            }
                        }
                        else
                        {
                            _autoResetEvent.WaitOne();
                            StartCallHandler(callInfo);
                        }
                    }
                }
            });
        }

        void StartCallHandler(CallInfo callInfo)
        {
            lock (_sync)
            {
                ++_currentConcurrentCall;
                var callHandler = new CallHandler(_softphone, callInfo);
                callHandler.Completed += callHandler_Completed;
                callHandler.ReadyToCall += callHandler_ReadyToCall;
                _callHandlers.Add(callHandler);

                callHandler.Start();
            }
        }

        void callHandler_ReadyToCall(object sender, EventArgs e)
        {
            _nextCall.Set();
        }

        void callHandler_Completed(object sender, EventArgs e)
        {
            lock (_sync)
            {
                _callHandlers.Remove((CallHandler)sender);
                --_currentConcurrentCall;
                _autoResetEvent.Set();
            }
        }

    }
}
