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 Random r = new Random();

        static volatile bool watekProducentaAktywny = true;
        static volatile bool watekKonsumentaAktywny = true;
        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 = 1;

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

        static void wyswietlStanWatkow()
        {
            //Console.WriteLine("Watek producenta jest " + (watekProducentaAktywny ? "aktywny" : "uśpiony") + ", watek konsumenta jest " + (watekKonsumentaAktywny ? "aktywny" : "uśpiony"));
        }

        static void Main(string[] args)
        {
            ThreadStart akcjaProducenta =
                () =>
                {
                    Console.WriteLine("Wątek producenta jest uruchamiany");
                    while (true)
                    {
                        if (watekProducentaAktywny) Thread.Sleep(r.Next(maksymalnyCzasUruchomieniaProdukcji));
                        while (watekProducentaAktywny)
                        {
                            lock (obiektSynchronizacjiMagazynu)
                            {
                                licznikElementowWMagazynie++;
                                Console.Write("Element dodany. ");                                
                            }
                            wyswietlStanMagazynu();                            
                            if (licznikElementowWMagazynie >= pojemnoscMagazynu)
                            {
                                watekProducentaAktywny = false;
                                Console.WriteLine("Wątek producenta został uśpiony");
                            }                                
                            if (!watekKonsumentaAktywny)
                            {                                
                                Console.WriteLine("Wątek konsumenta jest wznawiany");                                
                                watekKonsumentaAktywny = true;
                            }
                            wyswietlStanWatkow();
                            Thread.Sleep(r.Next(maksymalnyCzasProdukcji));
                        }
                    }                    
                };

            ThreadStart akcjaKonsumenta =
                () =>
                {
                    Console.WriteLine("Wątek konsumenta jest uruchamiany");
                    while (true)
                    {
                        if(watekKonsumentaAktywny) Thread.Sleep(r.Next(maksymalnyCzasUruchomieniaKonsumpcji));                        
                        while (watekKonsumentaAktywny)
                        {
                            lock (obiektSynchronizacjiMagazynu)
                            {
                                licznikElementowWMagazynie--;
                                Console.Write("Element zabrany. ");                                
                            }
                            wyswietlStanMagazynu();                            
                            if (licznikElementowWMagazynie <= 0)
                            {
                                watekKonsumentaAktywny = false;
                                Console.WriteLine("Wątek konsumenta został uśpiony");
                            }
                            if (!watekProducentaAktywny)
                            {                                
                                Console.WriteLine("Wątek producenta jest wznawiany");                                
                                watekProducentaAktywny = true;
                            }
                            wyswietlStanWatkow();
                            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();
        }
    }
}
