namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter19.Listing19_30
{
    using AddisonWesley.Michaelis.EssentialCSharp.Shared;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;

    public class Program
    {
        public static void Main()
        {
            EncryptFiles($@"{Directory.GetCurrentDirectory()}\..\..\", "*.*");
        }

        static void EncryptFiles(
            string directoryPath, string searchPattern)
        {

            string stars =
                "*".PadRight(Console.WindowWidth - 1, '*');

            IEnumerable<string> files = Directory.GetFiles(
               directoryPath, searchPattern,
               SearchOption.AllDirectories);

            CancellationTokenSource cts =
                new CancellationTokenSource();
            ParallelOptions parallelOptions =
                new ParallelOptions { CancellationToken = cts.Token };
            cts.Token.Register(
                () => Console.WriteLine("Anulowanie..."));

            Console.WriteLine("Wciśnij ENTER, aby zakończyć.");

            // Aby zastosować bibliotekę TPL w wersjach starszych niż .NET 4.5, 
            // wywołaj metodę Task.Factory.StartNew<string>().
            Task task = Task.Run(() =>
                {
                    try
                    {
                        Parallel.ForEach(
                            files, parallelOptions,
                            (fileName, loopState) =>
                            {
                                Encrypt(fileName);
                            });
                    }
                    catch(OperationCanceledException) { }
                });

            // Oczekiwanie na dane wyjściowe od użytkownika.
            Console.Read();

            // Anulowanie kwerendy.
            cts.Cancel();
            Console.Write(stars);
            task.Wait();
        }

        private static void Encrypt(string fileName)
        {
            if (Path.GetExtension(fileName) == ".encrypt") return;
            Console.WriteLine($">>>>>Trwa szyfrowanie pliku '{ fileName }'.");
            Cryptographer cryptographer = new Cryptographer();
            File.Delete($"{fileName}.encrypt");
            byte[] encryptedText = cryptographer.Encrypt(File.ReadAllBytes(fileName));
            File.WriteAllBytes($"{fileName}.encrypt", encryptedText);
            Console.WriteLine($"<<<<<Zakończono szyfrowanie pliku '{ fileName}'.");
        }
    }
}


