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 AsyncDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        void msgBox(string komunikat)
        {
            string taskID = Task.CurrentId.HasValue ? Task.CurrentId.ToString() : "UI";
            MessageBox.Show("! " + komunikat + " (" + taskID + ")");
        }

        //*
        Task<long> DoSomethingAsync(object argument)
        {
            Func<object, long> akcja =
                (object _argument) =>
                {
                    msgBox("Akcja: Początek, argument: " + _argument.ToString());
                    Thread.Sleep(1000); //opóźnienie                    
                    msgBox("Akcja: Koniec");
                    return DateTime.Now.Ticks;
                };

            Task<long> zadanie = new Task<long>(akcja, argument);
            zadanie.Start();            
            return zadanie;
        }
        //*/

        /*
        Task DoSomethingAsyncVoid(object argument)
        {
            Action<object> akcja =
                (object _argument) =>
                {
                    msgBox("Akcja: Początek, argument: " + _argument.ToString());
                    Thread.Sleep(1000); //opóźnienie
                    msgBox("Akcja: Koniec");
                };

            Task zadanie = new Task(akcja, argument);
            zadanie.Start();
            return zadanie;
        }
        */

        private async void button1_Click(object sender, EventArgs e)
        {
            /*
            Func<object, long> akcja =
                (object argument) =>
                {
                    msgBox("Akcja: Początek, argument: " + argument.ToString());
                    Thread.Sleep(1000); //opóźnienie
                    msgBox("Akcja: Koniec");
                    return DateTime.Now.Ticks;
                };
            */

            msgBox("button1_Click: Początek");

            /*
            //1) akcja wykonywana synchronicznie            
            msgBox("Wynik: "+akcja("synchronicznie"));
            */

            //Thread watek = new Thread(new ParameterizedThreadStart(akcja)); //tu: akcja nie moze zwracac wartosci
            //watek.Start("watek");
            //msgBox("Watek został uruchomiony");

            /*
            //2) akcja wykonywana asynchronicznie przez zadanie
            Task<long> zadanie = new Task<long>(akcja, "zadanie");
            zadanie.Start();
            msgBox("Akcja została uruchomiona");
            //własność Result czeka ze zwróceniem wartości aż zadanie zostanie zakończone (synchronizacja)
            if (zadanie.Status != TaskStatus.Running && zadanie.Status!=TaskStatus.RanToCompletion) msgBox("Zadanie nie zostało uruchomione");
            else msgBox("Wynik: "+zadanie.Result);            
            */

            /*
            //3) akcja wykonywana asynchronicznie przez zadanie - metoda tworzaca zadanie
            Task<long> zadanie = DoSomethingAsync("zadanie-metoda");
            msgBox("Akcja została uruchomiona");
            msgBox("Stan akcji: " + zadanie.Status.ToString());
            if (zadanie.Status != TaskStatus.Running && zadanie.Status!=TaskStatus.RanToCompletion) msgBox("Zadanie nie zostało uruchomione");
            else msgBox("Wynik: " + zadanie.Result);
            */

            /*
            //4) akcja wykonywana asynchronicznie - async/await
            Task<long> zadanie = DoSomethingAsync("async/await");
            msgBox("Akcja została uruchomiona");
            long wynik = await zadanie;
            msgBox("Wynik: " + wynik);
            */

            //*
            //5) akcja wykonywana asynchronicznie - async/await bez Task
            long wynik = await DoSomethingAsync("async/await");
            msgBox("Wynik: " + wynik.ToString());
            //*/

            /*
            //6) akcja wykonywana asynchronicznie - async/await bez Task
            await DoSomethingAsyncVoid("async/await");
            msgBox("Po wykonaniu zadania");
            */

            msgBox("button1_Click: Koniec");
        }

        /*
        private async Task button1ClickAsync()
        {
            msgBox("button1ClickAsync: Początek");
            long wynik = await DoSomethingAsync("async/await");
            msgBox("button1ClickAsync: Wynik: " + wynik.ToString());
            msgBox("button1ClickAsync: Koniec");            
            return;
        }
        */

        private async Task<long> DoSomethingMoreAsync()
        {
            msgBox("DoSomethingMoreAsync: Początek");
            //throw new Exception("Błąd w metodzie DoSomethingMoreAsync");
            long wynik = await DoSomethingAsync("async/await");            
            msgBox("DoSomethingMoreAsync: Wynik: " + wynik.ToString());
            msgBox("DoSomethingMoreAsync: Koniec");
            return wynik;
        }

        private async void button2_Click(object sender, EventArgs e)
        {            
            msgBox("button2_Click: Początek");
            //button1_Click(null, null);
            //await DoSomethingMoreAsync();
            try
            {
                msgBox("button2_Click: Wynik: " + await DoSomethingMoreAsync());
            }
            catch(Exception exc)
            {
                msgBox("button2_Click: Błąd!\n" + exc.Message);
            }
            msgBox("button2_Click: Koniec");
        }

    }
}
