using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace Operators
{
    class Examples39_46
    {
        public static void GetAverage()
        {
            // Listing 10-39
            Console.WriteLine("Średnia długość kursu w godzinach: {0}",
                Course.Catalog.Average(course => course.Duration.TotalHours));
        }

        public static void GetMaxWithProjection()
        {
            var mathsCourses = Course.Catalog.Where(c => c.Category == "MAT");

            // Listing 10-40
            DateTime m = mathsCourses.Max(c => c.PublicationDate);

            Console.WriteLine(m);
        }

        public static void SumAndAggregate()
        {
            // Listing 10-41
            double t1 = Course.Catalog.Sum(course => course.Duration.TotalHours);
            double t2 = Course.Catalog.Aggregate(
                0.0, (hours, course) => hours + course.Duration.TotalHours);

            Console.WriteLine("{0}, {1}", t1, t2);
        }

        public static void MaxWithAggregate()
        {
            var mathsCourses = Course.Catalog.Where(c => c.Category == "MAT");

            // Listing 10-42
            DateTime m = mathsCourses.Aggregate(
                new DateTime(),
               (date, c) => date > c.PublicationDate ? date : c.PublicationDate);

            Console.WriteLine(m);
        }

        public static void AverageWithAggregate()
        {
            // Listing 10-43
            double average = Course.Catalog.Aggregate(
                new { TotalHours = 0.0, Count = 0 },
                (totals, course) => new
                {
                    TotalHours = totals.TotalHours + course.Duration.TotalHours,
                    Count = totals.Count + 1
                },
                totals => totals.TotalHours / totals.Count);

            Console.WriteLine(average);
        }

        // Listing 10-44
        public static Rect GetBounds(IEnumerable<Rect> rects)
        {
            return rects.Aggregate(Rect.Union);
        }

        public static void CalcluateBoundingBoxWithAggregate()
        {
            Rect r1 = new Rect(100, 100, 5, 200);
            Rect r2 = new Rect(90, 50, 60, 10);
            Rect r3 = new Rect(100, 30, 20, 10);
            Rect r4 = new Rect(105, 10, 200, 10);
            Rect boundingBox = GetBounds(new[] { r1, r2, r3, r4 });
            Console.WriteLine(boundingBox);


            Console.WriteLine(MoreVerbose.GetBounds(new[] { r1, r2, r3, r4 }));
        }

        // By uniknąć konfliktu nazw, następny przykład jest klasą
        class MoreVerbose
        {
            // Listing 10-45
            public static Rect GetBounds(IEnumerable<Rect> rects)
            {
                IEnumerable<Rect> theRest = rects.Skip(1);
                return theRest.Aggregate(rects.First(), (r1, r2) => Rect.Union(r1, r2));
            }
        }

        public static void ExplicitExpansionOfBoundingBoxAggregation()
        {
            Rect r1 = new Rect(100, 100, 5, 200);
            Rect r2 = new Rect(90, 50, 60, 10);
            Rect r3 = new Rect(100, 30, 20, 10);
            Rect r4 = new Rect(105, 10, 200, 10);
            Rect bounds = Rect.Union(Rect.Union(Rect.Union(r1, r2), r3), r4);
            Console.WriteLine(bounds);
        }
    }
}
