using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Threading;

namespace ProducentKonsument
{
    class Program
    {        
        static object obiektSynchronizacjiMagazynu = new object();
        static object obiektSynchronizacjiProducenta = new object();
        static object obiektSynchronizacjiKonsumenta = new object();
        static Random r = new Random();

        static Thread watekProducenta = null;
        static Thread watekKonsumenta = null;

        const int maksymalnyCzasProdukcji = 1000;
        const int maksymalnyCzasKonsumpcji = 1000;
        const int maksymalnyCzasUruchomieniaProdukcji = 5000;
        const int maksymalnyCzasUruchomieniaKonsumpcji = 5000;

        static int pojemnoscMagazynu = 20;
        static int licznikElementowWMagazynie = 10;

        static void wyswietlStanMagazynu()
        {
            Console.WriteLine("Liczba elementów w magazynie: " + licznikElementowWMagazynie.ToString());
        }

        static void Main(string[] args)
        {
            ThreadStart akcjaProducenta =
                () =>
                {
                    Console.WriteLine("Wątek producenta jest uruchamiany");
                    while (true)
                    {
                        lock (obiektSynchronizacjiMagazynu)
                        {
                            licznikElementowWMagazynie++;
                            Console.Write("Element dodany. ");
                        }
                        wyswietlStanMagazynu();
                        if (licznikElementowWMagazynie >= pojemnoscMagazynu)
                        {
                            Console.WriteLine("Wątek producenta zostanie uśpiony");
                            lock (obiektSynchronizacjiProducenta) Monitor.Wait(obiektSynchronizacjiProducenta);
                            Console.WriteLine("Wątek producenta zostanie wznowiony");
                            Thread.Sleep(r.Next(maksymalnyCzasUruchomieniaProdukcji));                            
                            Console.WriteLine("Wątek producenta został wznowiony");
                        }
                        lock (obiektSynchronizacjiKonsumenta) Monitor.Pulse(obiektSynchronizacjiKonsumenta);
                        Thread.Sleep(r.Next(maksymalnyCzasProdukcji));
                    }
                };

            ThreadStart akcjaKonsumenta =
                () =>
                {
                    Console.WriteLine("Wątek konsumenta jest uruchamiany");
                    while (true)
                    {
                        lock (obiektSynchronizacjiMagazynu)
                        {
                            licznikElementowWMagazynie--;
                            Console.Write("Element zabrany. ");
                        }
                        wyswietlStanMagazynu();
                        if (licznikElementowWMagazynie <= 0)
                        {
                            Console.WriteLine("Wątek konsumenta zostanie uśpiony");
                            lock (obiektSynchronizacjiKonsumenta) Monitor.Wait(obiektSynchronizacjiKonsumenta);
                            Console.WriteLine("Wątek konsumenta zostanie wznowiony");
                            Thread.Sleep(r.Next(maksymalnyCzasUruchomieniaKonsumpcji));
                            Console.WriteLine("Wątek konsumenta został wznowiony");
                        }
                        lock (obiektSynchronizacjiProducenta) Monitor.Pulse(obiektSynchronizacjiProducenta);
                        Thread.Sleep(r.Next(maksymalnyCzasKonsumpcji));
                    }
                };

            watekProducenta = new Thread(akcjaProducenta);
            watekProducenta.IsBackground = true;
            watekProducenta.Start();             

            watekKonsumenta = new Thread(akcjaKonsumenta);
            watekKonsumenta.IsBackground = true;
            watekKonsumenta.Start();            

            Console.ReadLine();
            Console.Write("Koniec. "); wyswietlStanMagazynu();
        }
    }
}
