using System;
using System.Threading;
using Microsoft.SPOT;

namespace CPF
{
    public class SynchronizedEventQueue
    {
        protected EventQueue     _anEventQ;
        private int             _consumersWaiting;
        private int             _producersWaiting;
        private AutoResetEvent  _available;

        public SynchronizedEventQueue(int capacity)
        {
            _anEventQ = new EventQueue(capacity);
            _available = new AutoResetEvent(false);
            _consumersWaiting = 0;
            _producersWaiting = 0;
        }

        public bool Empty()
        {
            bool emptyQ;
            lock (_anEventQ)
            {
                emptyQ = _anEventQ.Empty();
            }
            return emptyQ;
        }

        public void Add(Signal s, double dval, int ival)
        {
            Monitor.Enter(_anEventQ);
            try
            {
                while (_anEventQ.Full())
                {
                    _producersWaiting++;
                    Monitor.Exit(_anEventQ);
                    _available.WaitOne();
                    Monitor.Enter(_anEventQ);
                    _producersWaiting--;
                }
                _anEventQ.Insert(s,dval,ival);
                if (_consumersWaiting > 0)
                    _available.Set();
            }
            finally
            {
                Monitor.Exit(_anEventQ);
            }
        }

        public Event Remove()
        {
            Event item;
            Monitor.Enter(_anEventQ);
            try
            {
                while (_anEventQ.Empty())
                {
                    _consumersWaiting++;
                    Monitor.Exit(_anEventQ);
                    _available.WaitOne();
                    Monitor.Enter(_anEventQ);
                    _consumersWaiting--;
                }
                item = _anEventQ.Delete();
                if (_producersWaiting > 0)
                    _available.Set();
            }
            finally
            {
                Monitor.Exit(_anEventQ);
            }
            return item;
        }
    }
}
