using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Threading;

namespace KontekstSynchronizacji_WinForm
{
    public partial class Form1 : Form
    {
        static int min = 0;
        static int max = 100;
        static int opoznienie = 100;

        public Form1()
        {
            InitializeComponent();            

            resetujInterfejs(null, null);
        }

        private void resetujInterfejs(object sender, EventArgs e)
        {
            progressBar1.Minimum = min;
            progressBar1.Maximum = max;
            progressBar1.Value = min;
            button1.Text = "Synchronicznie";
            button2.Text = "InvokeRequire / Invoke";
            button3.Text = "Kontekst synchronizacji";
        }

        #region Synchronicznie
        private void kontrolaPaskaPostepu()
        {
            for (int i = min; i <= max; i++)
            {
                progressBar1.Value = i;
                Thread.Sleep(opoznienie);
            }
            button1.Text = "Koniec";
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //synchronicznie
            kontrolaPaskaPostepu();
        }
        #endregion

        #region Asynchronicznie - Invoke
        //private delegate void BezpiecznieUstawWartoscPaskaPostepuDelegate(ProgressBar progressBar, int nowaWartosc);

        public static void ustawWartoscPaskaPostepu_Invoke(ProgressBar progressBar, int nowaWartosc)
        {
            if (progressBar == null) return;
            //MessageBox.Show("InvokeRequired: " + progressBar.InvokeRequired.ToString());
            if (progressBar.InvokeRequired)
            {
                progressBar.Invoke(
                //progressBar.BeginInvoke(
                    //new BezpiecznieUstawWartoscPaskaPostepuDelegate(ustawWartoscPaskaPostepu_Invoke), 
                    new Action<ProgressBar,int>(ustawWartoscPaskaPostepu_Invoke), 
                    new object[] { progressBar, nowaWartosc });
            }
            else
            {
                progressBar.Value = nowaWartosc;
            }
        }

        private void kontrolaPaskaPostepu_Invoke(object parametr)
        {
            bool czyBezpiecznie = (bool)parametr;
            for (int i = min; i <= max; i++)
            {
                if (czyBezpiecznie) ustawWartoscPaskaPostepu_Invoke(progressBar1, i);
                else progressBar1.Value = i;
                Thread.Sleep(opoznienie);
            }

            button2.Invoke(new Action(() => { button2.Text = "Koniec"; }));
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //watek
            Thread t = new Thread(kontrolaPaskaPostepu_Invoke);
            t.Start(checkBox1.Checked);
            
            //zakleszczenie
            //t.Join();
            //button2.Text = "Zakleszczenie";
        }
        #endregion

        #region Wątek + Kontekst synchronizacji
        private void ustawWartoscPaskaPostepu_KontekstSynchronizacji(object parametr)
        {
            //to dziala w watku UI
            int nowaWartosc = (int)parametr;
            progressBar1.Value = nowaWartosc;            
        }

        private void kontrolaPaskaPostepu_KontekstSynchronizacji(object parametr)
        {
            //MessageBox.Show(SynchronizationContext.Current.ToString());

            SynchronizationContext kontekst = parametr as SynchronizationContext;
            
            for (int i = min; i <= max; i++)
            {
                if (checkBox2.Checked)
                {
                    try
                    {
                        //uruchamia funkcje zwrotna w wątku okna i czeka na jego zakonczenie
                        //wyjątek pojawi się tutaj
                        kontekst.Send(ustawWartoscPaskaPostepu_KontekstSynchronizacji, i);
                        //kontekst.Send((object nowaWartosc) => { progressBar1.Value = (int)nowaWartosc; }, i);
                    }
                    catch (Exception exc)
                    {
                        MessageBox.Show("Wyjątek: " + exc.Message);
                    }
                }
                else
                {
                    //przesyla kod do watku okna i uruchamia asynchronicznie
                    //wyjatek pojawi się w wątku pierwotnym
                    kontekst.Post(ustawWartoscPaskaPostepu_KontekstSynchronizacji, i);
                }
                Thread.Sleep(opoznienie);
            }

            //button3.Invoke(new Action(() => { button3.Text = "Koniec"; }));
            kontekst.Send((object niewykorzystany) => { button3.Text = "Koniec"; }, null);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            //MessageBox.Show(SynchronizationContext.Current.ToString());

            SynchronizationContext kontekst = SynchronizationContext.Current;

            //watek z kontekstem synchronizacji
            Thread t = new Thread(kontrolaPaskaPostepu_KontekstSynchronizacji);
            t.Start(kontekst);
            
            //zakleszczenie przy sens
            //t.Join();
            //button3.Text = "Zakleszczenie";
        }
        #endregion

    }
}
