// ========================================================================
//
// Copyright (C) 2016-2017 MARC CHEVALDONNE
//                         marc.chevaldonne.free.fr
//
// Module        : Program.cs
// Author        : Marc Chevaldonné
// Creation date : 2016-10-08
//
// ========================================================================

using System;
using static System.Console;
using nsUtils;

namespace ex_028_015_Action
{
    /// <summary>
    /// .NET contient déjà un certain nombre de types délégués dans l'espace de noms System.
    /// Parmi eux, on peut distinguer notamment la famille des Predicate, des Func et des Action.
    /// Cet exemple présente le délégué Action.
    /// 
    /// Le délégué Action est multi-générique et a la forme suivante :
    /// delegate TResult Action<T1, T2, T3>(T1 arg1, T2 arg2, T3 arg3);
    /// Mais il y en a de nombreux dans le framework :
    /// Action<T>
    /// Action<T1, T2>
    /// Action<T1, T2, T3>
    /// Action<T1, T2, T3, T4>
    /// Action<T1, T2, T3, T4, T5>
    /// Action<T1, T2, T3, T4, T5, ..., T16>
    /// 
    /// N'importe quelle instance d'un Action<T1, ..., Ti> est donc une méthode prenant en paramètres 
    /// un T1, un T2, un T3, ... un Ti et ne rendant rien (void).
    /// 
    /// Comme Predicate et Func, ils sont très utilisés avec LINQ (chap 31) et profitent des méthodes anonymes (chap. 30)
    /// 
    /// Cet exemple reprend l'exemple ex_028_009 en utilisant le délégué Action<int>
    /// </summary>
    class Program
    {
        /// <summary>
        /// méthode de type délégué Progression (elle prend un entier et ne renvoie rien) qui affiche le pourcentage de progression
        /// </summary>
        /// <param name="pourcentage">pourcentage de progression</param>
        static void AffichePourcentage(int pourcentage)
        {
            WriteLine($"{pourcentage}% effectués...");
        }

        /// <summary>
        /// méthode de type délégué Progression (elle prend un entier et ne renvoie rien) qui affiche des étoiles en fonction du pourcentage de progression
        /// </summary>
        /// <param name="pourcentage">pourcentage de progression</param>
        static void ProgressBar(int pourcentage)
        {
            WriteLine(String.Empty.PadLeft(pourcentage * (WindowWidth - 1) / 100, '*'));
        }

        static void Main(string[] args)
        {
            WriteLine("Lancement du gros travail");
            ClasseQuiFaitDuGrosTravail travail = new ClasseQuiFaitDuGrosTravail();
            travail.GrosTravail();
            WriteLine("fini");

            //on prépare une instance de délégué du type délégué Progression pointant sur une seule méthode AffichePourcentage,
            //et on appelle la méthode GrosTravail avec cette instance en paramètre.
            WriteLine("PREMIER APPEL");
            travail.Attacher(AffichePourcentage);
            travail.GrosTravail();

            //on ajoute une instance de délégué à notre "pointeur" : ProgressBar.
            //L'instance de délégué p pointe maintenant sur deux méthodes qui sont exécutées l'une après l'autre à chaque appel.
            //On appelle la méthode GrosTravail avec cette instance en paramètre.
            WriteLine("DEUXIEME APPEL");
            travail.Attacher(ProgressBar);
            travail.GrosTravail();

            //on retire une instance de délégué à notre "pointeur" : AffichePourcentagen.
            //L'instance de délégué p pointe maintenant sur une seule méthode (ProgressBar).
            //On appelle la méthode GrosTravail avec cette instance en paramètre.
            WriteLine("TROISIEME APPEL");
            travail.Détacher(AffichePourcentage);
            travail.GrosTravail();

            //on réinitialise p avec la méthode ClearConsole, puis on ajoute ProgressBar, puis AffichePourcentage
            travail.Initialiser((i) => Clear());
            travail.Attacher(ProgressBar);
            travail.Attacher(AffichePourcentage);
            travail.GrosTravail();
        }

        static void ClearConsole(int pourcentage)
        {
            Clear();
        }
    }
}
